108#define DEBUG_TYPE "amdgpu-sw-lower-lds"
109#define COV5_HIDDEN_DYN_LDS_SIZE_ARG 15
117 AsanInstrumentLDS(
"amdgpu-asan-instrument-lds",
118 cl::desc(
"Run asan instrumentation on LDS instructions "
119 "lowered to global memory"),
124struct LDSAccessTypeInfo {
132struct KernelLDSParameters {
136 LDSAccessTypeInfo DirectAccess;
137 LDSAccessTypeInfo IndirectAccess;
139 LDSToReplacementIndicesMap;
147struct NonKernelLDSParameters {
154struct AsanInstrumentInfo {
160struct FunctionsAndLDSAccess {
168class AMDGPUSwLowerLDS {
170 AMDGPUSwLowerLDS(
Module &
Mod, DomTreeCallback Callback)
171 : M(
Mod), IRB(M.getContext()), DTCallback(Callback) {}
173 void getUsesOfLDSByNonKernels();
174 void getNonKernelsWithLDSArguments(
const CallGraph &CG);
179 void buildSwLDSGlobal(
Function *Func);
180 void buildSwDynLDSGlobal(
Function *Func);
181 void populateSwMetadataGlobal(
Function *Func);
182 void populateSwLDSAttributeAndMetadata(
Function *Func);
183 void populateLDSToReplacementIndicesMap(
Function *Func);
184 void getLDSMemoryInstructions(
Function *Func,
186 void replaceKernelLDSAccesses(
Function *Func);
187 Value *getTranslatedGlobalMemoryPtrOfLDS(
Value *LoadMallocPtr,
Value *LDSPtr);
188 void translateLDSMemoryOperationsToGlobalMemory(
193 void buildNonKernelLDSOffsetTable(NonKernelLDSParameters &NKLDSParams);
194 void buildNonKernelLDSBaseTable(NonKernelLDSParameters &NKLDSParams);
196 getAddressesOfVariablesInKernel(
Function *Func,
198 void lowerNonKernelLDSAccesses(
Function *Func,
200 NonKernelLDSParameters &NKLDSParams);
202 updateMallocSizeForDynamicLDS(
Function *Func,
Value **CurrMallocSize,
203 Value *HiddenDynLDSSize,
210 DomTreeCallback DTCallback;
211 FunctionsAndLDSAccess FuncLDSAccessInfo;
212 AsanInstrumentInfo AsanInfo;
215template <
typename T>
SetVector<T> sortByName(std::vector<T> &&V) {
218 sort(V, [](
const auto *L,
const auto *R) {
219 return L->getName() < R->getName();
228 std::vector<GlobalVariable *>(Variables.
begin(), Variables.
end()));
236 if (Kernels.size() > UINT32_MAX) {
240 sortByName(std::vector<Function *>(Kernels.begin(), Kernels.end()));
241 for (
size_t i = 0; i < Kernels.size(); i++) {
246 Func->setMetadata(
"llvm.amdgcn.lds.kernel.id",
249 return OrderedKernels;
252void AMDGPUSwLowerLDS::getNonKernelsWithLDSArguments(
const CallGraph &CG) {
256 for (
auto &
K : FuncLDSAccessInfo.KernelToLDSParametersMap) {
261 for (
auto &
I : *CGN) {
270 Type *ArgTy = (*AI).getType();
275 FuncLDSAccessInfo.NonKernelsWithLDSArgument.
insert(CalledFunc);
278 FuncLDSAccessInfo.KernelsWithIndirectLDSAccess.
insert(Func);
284void AMDGPUSwLowerLDS::getUsesOfLDSByNonKernels() {
285 for (
GlobalVariable *GV : FuncLDSAccessInfo.AllNonKernelLDSAccess) {
293 FuncLDSAccessInfo.NonKernelToLDSAccessMap[
F].insert(GV);
307 ConstantInt::get(IntTy, Address + 1));
308 GV->
setMetadata(LLVMContext::MD_absolute_symbol, MetadataNode);
319 Func->addFnAttr(
"amdgpu-lds-size", Buffer);
325 IRBuilder<> Builder(Entry, Entry->getFirstNonPHIIt());
328 Intrinsic::donothing, {});
330 Value *UseInstance[1] = {
331 Builder.CreateConstInBoundsGEP1_32(SGV->getValueType(), SGV, 0)};
333 Builder.CreateCall(Decl, {},
337void AMDGPUSwLowerLDS::buildSwLDSGlobal(
Function *Func) {
340 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
348 LDSParams.SwLDS->setSanitizerMetadata(MD);
351void AMDGPUSwLowerLDS::buildSwDynLDSGlobal(
Function *Func) {
353 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
354 if (LDSParams.DirectAccess.DynamicLDSGlobals.empty() &&
355 LDSParams.IndirectAccess.DynamicLDSGlobals.empty())
361 "llvm.amdgcn." + Func->getName() +
".dynlds",
nullptr,
363 markUsedByKernel(Func, LDSParams.SwDynLDS);
366 LDSParams.SwDynLDS->setSanitizerMetadata(MD);
369void AMDGPUSwLowerLDS::populateSwLDSAttributeAndMetadata(
Function *Func) {
370 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
371 bool IsDynLDSUsed = LDSParams.SwDynLDS;
373 recordLDSAbsoluteAddress(M, LDSParams.SwLDS, 0);
374 addLDSSizeAttribute(Func,
Offset, IsDynLDSUsed);
375 if (LDSParams.SwDynLDS)
376 recordLDSAbsoluteAddress(M, LDSParams.SwDynLDS,
Offset);
379void AMDGPUSwLowerLDS::populateSwMetadataGlobal(
Function *Func) {
382 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
383 auto &Ctx = M.getContext();
384 auto &
DL = M.getDataLayout();
385 std::vector<Type *> Items;
387 std::vector<Constant *> Initializers;
388 Align MaxAlignment(1);
391 MaxAlignment = std::max(MaxAlignment, GVAlign);
394 for (
GlobalVariable *GV : LDSParams.DirectAccess.StaticLDSGlobals)
395 UpdateMaxAlignment(GV);
397 for (
GlobalVariable *GV : LDSParams.DirectAccess.DynamicLDSGlobals)
398 UpdateMaxAlignment(GV);
400 for (
GlobalVariable *GV : LDSParams.IndirectAccess.StaticLDSGlobals)
401 UpdateMaxAlignment(GV);
403 for (
GlobalVariable *GV : LDSParams.IndirectAccess.DynamicLDSGlobals)
404 UpdateMaxAlignment(GV);
409 MDItemOS <<
"llvm.amdgcn.sw.lds." << Func->getName() <<
".md.item";
413 uint32_t &MallocSize = LDSParams.MallocSize;
415 int AsanScale = AsanInfo.Scale;
416 auto buildInitializerForSwLDSMD =
418 for (
auto &GV : LDSGlobals) {
421 UniqueLDSGlobals.
insert(GV);
424 const uint64_t SizeInBytes =
DL.getTypeAllocSize(Ty);
425 Items.push_back(LDSItemTy);
426 Constant *ItemStartOffset = ConstantInt::get(Int32Ty, MallocSize);
427 Constant *SizeInBytesConst = ConstantInt::get(Int32Ty, SizeInBytes);
432 MallocSize += SizeInBytes;
434 LDSParams.RedzoneOffsetAndSizeVector.emplace_back(MallocSize,
436 MallocSize += RightRedzoneSize;
439 alignTo(SizeInBytes + RightRedzoneSize, MaxAlignment);
441 ConstantInt::get(Int32Ty, AlignedSize);
443 MallocSize =
alignTo(MallocSize, MaxAlignment);
446 AlignedSizeInBytesConst});
447 Initializers.push_back(InitItem);
451 SwLDSVector.
insert(LDSParams.SwLDS);
452 buildInitializerForSwLDSMD(SwLDSVector);
453 buildInitializerForSwLDSMD(LDSParams.DirectAccess.StaticLDSGlobals);
454 buildInitializerForSwLDSMD(LDSParams.IndirectAccess.StaticLDSGlobals);
455 buildInitializerForSwLDSMD(LDSParams.DirectAccess.DynamicLDSGlobals);
456 buildInitializerForSwLDSMD(LDSParams.IndirectAccess.DynamicLDSGlobals);
459 Type *Ty = LDSParams.SwLDS->getValueType();
460 const uint64_t SizeInBytes =
DL.getTypeAllocSize(Ty);
462 LDSParams.LDSSize = AlignedSize;
465 MDTypeOS <<
"llvm.amdgcn.sw.lds." << Func->getName() <<
".md.type";
470 MDOS <<
"llvm.amdgcn.sw.lds." << Func->getName() <<
".md";
476 LDSParams.SwLDSMetadata->setInitializer(
data);
479 LDSParams.SwLDS->setAlignment(MaxAlignment);
480 if (LDSParams.SwDynLDS)
481 LDSParams.SwDynLDS->setAlignment(MaxAlignment);
484 LDSParams.SwLDSMetadata->setSanitizerMetadata(MD);
487void AMDGPUSwLowerLDS::populateLDSToReplacementIndicesMap(
Function *Func) {
490 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
494 for (
auto &GV : LDSGlobals) {
497 UniqueLDSGlobals.
insert(GV);
498 LDSParams.LDSToReplacementIndicesMap[GV] = {0, Idx, 0};
504 SwLDSVector.
insert(LDSParams.SwLDS);
505 PopulateIndices(SwLDSVector, Idx);
506 PopulateIndices(LDSParams.DirectAccess.StaticLDSGlobals, Idx);
507 PopulateIndices(LDSParams.IndirectAccess.StaticLDSGlobals, Idx);
508 PopulateIndices(LDSParams.DirectAccess.DynamicLDSGlobals, Idx);
509 PopulateIndices(LDSParams.IndirectAccess.DynamicLDSGlobals, Idx);
513 Value *Replacement) {
515 auto ReplaceUsesLambda = [Func](
const Use &U) ->
bool {
516 auto *V = U.getUser();
518 auto *Func1 = Inst->getFunction();
527void AMDGPUSwLowerLDS::replaceKernelLDSAccesses(
Function *Func) {
528 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
536 auto &IndirectAccess = LDSParams.IndirectAccess;
537 auto &DirectAccess = LDSParams.DirectAccess;
541 for (
auto &GV : LDSGlobals) {
544 if ((IndirectAccess.StaticLDSGlobals.contains(GV) ||
545 IndirectAccess.DynamicLDSGlobals.contains(GV)) &&
546 (!DirectAccess.StaticLDSGlobals.contains(GV) &&
547 !DirectAccess.DynamicLDSGlobals.contains(GV)))
551 UniqueLDSGlobals.
insert(GV);
552 auto &Indices = LDSParams.LDSToReplacementIndicesMap[GV];
553 assert(Indices.size() == 3);
554 Constant *GEPIdx[] = {ConstantInt::get(Int32Ty, Indices[0]),
555 ConstantInt::get(Int32Ty, Indices[1]),
556 ConstantInt::get(Int32Ty, Indices[2])};
558 Func->getDataLayout(), SwLDSMetadataStructType, SwLDSMetadata, GEPIdx,
561 Value *BasePlusOffset =
565 replacesUsesOfGlobalInFunction(Func, GV, BasePlusOffset);
568 ReplaceLDSGlobalUses(DirectAccess.StaticLDSGlobals);
569 ReplaceLDSGlobalUses(IndirectAccess.StaticLDSGlobals);
570 ReplaceLDSGlobalUses(DirectAccess.DynamicLDSGlobals);
571 ReplaceLDSGlobalUses(IndirectAccess.DynamicLDSGlobals);
574void AMDGPUSwLowerLDS::updateMallocSizeForDynamicLDS(
577 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
582 assert(SwLDS && SwLDSMetadata);
587 Value *MaxAlignValueMinusOne = IRB.
getInt32(MaxAlignment - 1);
590 auto &Indices = LDSParams.LDSToReplacementIndicesMap[DynGV];
592 Constant *Index0 = ConstantInt::get(Int32Ty, 0);
593 Constant *Index1 = ConstantInt::get(Int32Ty, Indices[1]);
595 Constant *Index2Offset = ConstantInt::get(Int32Ty, 0);
597 MetadataStructType, SwLDSMetadata, {Index0, Index1, Index2Offset});
601 Constant *Index2Size = ConstantInt::get(Int32Ty, 1);
603 {Index0, Index1, Index2Size});
607 Constant *Index2AlignedSize = ConstantInt::get(Int32Ty, 2);
609 MetadataStructType, SwLDSMetadata, {Index0, Index1, Index2AlignedSize});
611 Value *AlignedDynLDSSize =
612 IRB.
CreateAdd(CurrDynLDSSize, MaxAlignValueMinusOne);
613 AlignedDynLDSSize = IRB.
CreateUDiv(AlignedDynLDSSize, MaxAlignValue);
614 AlignedDynLDSSize = IRB.
CreateMul(AlignedDynLDSSize, MaxAlignValue);
615 IRB.
CreateStore(AlignedDynLDSSize, GEPForAlignedSize);
618 *CurrMallocSize = IRB.
CreateAdd(*CurrMallocSize, AlignedDynLDSSize);
632void AMDGPUSwLowerLDS::getLDSMemoryInstructions(
638 LDSInstructions.
insert(&Inst);
641 LDSInstructions.
insert(&Inst);
644 LDSInstructions.
insert(&Inst);
647 LDSInstructions.
insert(&Inst);
651 LDSInstructions.
insert(&Inst);
654 LDSInstructions.
insert(&Inst);
657 LDSInstructions.
insert(&Inst);
665Value *AMDGPUSwLowerLDS::getTranslatedGlobalMemoryPtrOfLDS(
Value *LoadMallocPtr,
667 assert(LDSPtr &&
"Invalid LDS pointer operand");
681void AMDGPUSwLowerLDS::translateLDSMemoryOperationsToGlobalMemory(
684 LLVM_DEBUG(
dbgs() <<
"Translating LDS memory operations to global memory : "
689 Value *LIOperand = LI->getPointerOperand();
691 getTranslatedGlobalMemoryPtrOfLDS(LoadMallocPtr, LIOperand);
693 IRB.
CreateLoad(LI->getType(), Replacement, LI->getProperties());
694 AsanInfo.Instructions.
insert(NewLI);
695 LI->replaceAllUsesWith(NewLI);
696 LI->eraseFromParent();
698 Value *SIOperand =
SI->getPointerOperand();
700 getTranslatedGlobalMemoryPtrOfLDS(LoadMallocPtr, SIOperand);
702 SI->getProperties());
703 AsanInfo.Instructions.
insert(NewSI);
704 SI->replaceAllUsesWith(NewSI);
705 SI->eraseFromParent();
707 Value *RMWPtrOperand = RMW->getPointerOperand();
708 Value *RMWValOperand = RMW->getValOperand();
710 getTranslatedGlobalMemoryPtrOfLDS(LoadMallocPtr, RMWPtrOperand);
712 RMW->getOperation(), Replacement, RMWValOperand, RMW->getAlign(),
713 RMW->getOrdering(), RMW->getSyncScopeID());
715 AsanInfo.Instructions.
insert(NewRMW);
716 RMW->replaceAllUsesWith(NewRMW);
717 RMW->eraseFromParent();
719 Value *XCHGPtrOperand = XCHG->getPointerOperand();
721 getTranslatedGlobalMemoryPtrOfLDS(LoadMallocPtr, XCHGPtrOperand);
723 Replacement, XCHG->getCompareOperand(), XCHG->getNewValOperand(),
724 XCHG->getAlign(), XCHG->getSuccessOrdering(),
725 XCHG->getFailureOrdering(), XCHG->getSyncScopeID());
727 AsanInfo.Instructions.
insert(NewXCHG);
728 XCHG->replaceAllUsesWith(NewXCHG);
729 XCHG->eraseFromParent();
731 Value *NewDest =
MI->getRawDest();
733 NewDest = getTranslatedGlobalMemoryPtrOfLDS(LoadMallocPtr, NewDest);
736 if (
MI->isAtomic()) {
738 NewDest, MSI->getValue(), MSI->getLength(),
739 MSI->getDestAlign().valueOrOne(), MSI->getElementSizeInBytes());
741 NewMI = IRB.
CreateMemSet(NewDest, MSI->getValue(), MSI->getLength(),
746 Value *NewSrc = MTI->getRawSource();
748 NewSrc = getTranslatedGlobalMemoryPtrOfLDS(LoadMallocPtr, NewSrc);
749 if (
MI->isAtomic()) {
750 if (
MI->getIntrinsicID() ==
751 Intrinsic::memmove_element_unordered_atomic) {
753 NewDest, MTI->getDestAlign().valueOrOne(), NewSrc,
754 MTI->getSourceAlign().valueOrOne(), MTI->getLength(),
755 MTI->getElementSizeInBytes());
758 NewDest, MTI->getDestAlign().valueOrOne(), NewSrc,
759 MTI->getSourceAlign().valueOrOne(), MTI->getLength(),
760 MTI->getElementSizeInBytes());
764 MI->getIntrinsicID(), NewDest, MTI->getDestAlign(), NewSrc,
765 MTI->getSourceAlign(), MTI->getLength(),
770 AsanInfo.Instructions.
insert(NewMI);
771 MI->replaceAllUsesWith(NewMI);
772 MI->eraseFromParent();
774 Value *AIOperand = ASC->getPointerOperand();
776 getTranslatedGlobalMemoryPtrOfLDS(LoadMallocPtr, AIOperand);
782 ASC->eraseFromParent();
788void AMDGPUSwLowerLDS::poisonRedzones(
Function *Func,
Value *MallocPtr) {
789 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
793 "__asan_poison_region",
796 auto RedzonesVec = LDSParams.RedzoneOffsetAndSizeVector;
797 size_t VecSize = RedzonesVec.size();
798 for (
unsigned i = 0; i < VecSize; i++) {
799 auto &RedzonePair = RedzonesVec[i];
800 uint64_t RedzoneOffset = RedzonePair.first;
801 uint64_t RedzoneSize = RedzonePair.second;
803 IRB.
getInt8Ty(), MallocPtr, {IRB.getInt64(RedzoneOffset)});
806 {RedzoneAddress, IRB.
getInt64(RedzoneSize)});
810void AMDGPUSwLowerLDS::lowerKernelLDSAccesses(
Function *Func,
812 LLVM_DEBUG(
dbgs() <<
"Sw Lowering Kernel LDS for : " << Func->getName());
813 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
814 auto &Ctx = M.getContext();
815 auto *PrevEntryBlock = &Func->getEntryBlock();
817 getLDSMemoryInstructions(Func, LDSInstructions);
831 auto SplitIt = PrevEntryBlock->getFirstNonPHIOrDbgOrAlloca();
832 WIdBlock->splice(WIdBlock->end(), PrevEntryBlock, PrevEntryBlock->begin(),
837 AI->moveBefore(*WIdBlock, WIdBlock->end());
852 IRB.
CreateCondBr(WIdzCond, MallocBlock, PrevEntryBlock);
862 assert(SwLDS && SwLDSMetadata);
870 for (
auto &GV : LDSGlobals) {
873 UniqueLDSGlobals.
insert(GV);
877 GetUniqueLDSGlobals(LDSParams.DirectAccess.StaticLDSGlobals);
878 GetUniqueLDSGlobals(LDSParams.IndirectAccess.StaticLDSGlobals);
881 unsigned LastStaticLDSIdx = UniqueLDSGlobals.
size();
882 UniqueLDSGlobals.
clear();
884 auto *GEPForEndStaticLDSOffset =
886 {ConstantInt::get(Int32Ty, 0),
887 ConstantInt::get(Int32Ty, LastStaticLDSIdx),
888 ConstantInt::get(Int32Ty, 0)});
890 auto *GEPForEndStaticLDSSize =
892 {ConstantInt::get(Int32Ty, 0),
893 ConstantInt::get(Int32Ty, LastStaticLDSIdx),
894 ConstantInt::get(Int32Ty, 2)});
896 Value *EndStaticLDSOffset = IRB.
CreateLoad(Int32Ty, GEPForEndStaticLDSOffset);
897 Value *EndStaticLDSSize = IRB.
CreateLoad(Int32Ty, GEPForEndStaticLDSSize);
898 Value *CurrMallocSize = IRB.
CreateAdd(EndStaticLDSOffset, EndStaticLDSSize);
900 if (LDSParams.SwDynLDS) {
903 "Dynamic LDS size query is only supported for CO V5 and later.");
909 {ConstantInt::get(Int64Ty, COV5_HIDDEN_DYN_LDS_SIZE_ARG)});
910 UniqueLDSGlobals.
clear();
911 GetUniqueLDSGlobals(LDSParams.DirectAccess.DynamicLDSGlobals);
912 GetUniqueLDSGlobals(LDSParams.IndirectAccess.DynamicLDSGlobals);
913 updateMallocSizeForDynamicLDS(Func, &CurrMallocSize, HiddenDynLDSSize,
917 CurrMallocSize = IRB.
CreateZExt(CurrMallocSize, Int64Ty);
922 Intrinsic::returnaddress, IRB.
getPtrTy(
DL.getProgramAddressSpace()),
928 Value *MallocCall = IRB.
CreateCall(MallocFunc, {CurrMallocSize, RAPtrToInt});
937 poisonRedzones(Func, MallocPtr);
945 auto *XYZCondPhi = IRB.
CreatePHI(Int1Ty, 2,
"xyzCond");
947 XYZCondPhi->addIncoming(IRB.
getInt1(1), MallocBlock);
952 Value *LoadMallocPtr =
956 replaceKernelLDSAccesses(Func);
960 translateLDSMemoryOperationsToGlobalMemory(Func, LoadMallocPtr,
969 RI->eraseFromParent();
989 Intrinsic::returnaddress, IRB.
getPtrTy(
DL.getProgramAddressSpace()),
993 IRB.
CreateCall(AsanFreeFunc, {MallocPtrToInt, RAPToInt});
1007Constant *AMDGPUSwLowerLDS::getAddressesOfVariablesInKernel(
1010 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
1014 auto *SwLDSMetadataStructType =
1020 for (
auto *GV : Variables) {
1021 auto It = LDSParams.LDSToReplacementIndicesMap.find(GV);
1022 if (It == LDSParams.LDSToReplacementIndicesMap.end()) {
1027 auto &Indices = It->second;
1028 Constant *GEPIdx[] = {ConstantInt::get(Int32Ty, Indices[0]),
1029 ConstantInt::get(Int32Ty, Indices[1]),
1030 ConstantInt::get(Int32Ty, Indices[2])};
1032 Func->getDataLayout(), SwLDSMetadataStructType, SwLDSMetadata, GEPIdx,
1034 Elements.push_back(
GEP);
1039void AMDGPUSwLowerLDS::buildNonKernelLDSBaseTable(
1040 NonKernelLDSParameters &NKLDSParams) {
1044 auto &Kernels = NKLDSParams.OrderedKernels;
1045 if (Kernels.empty())
1047 const size_t NumberKernels = Kernels.size();
1050 std::vector<Constant *> OverallConstantExprElts(NumberKernels);
1051 for (
size_t i = 0; i < NumberKernels; i++) {
1053 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
1054 OverallConstantExprElts[i] = LDSParams.SwLDS;
1067void AMDGPUSwLowerLDS::buildNonKernelLDSOffsetTable(
1068 NonKernelLDSParameters &NKLDSParams) {
1076 auto &Variables = NKLDSParams.OrdereLDSGlobals;
1077 auto &Kernels = NKLDSParams.OrderedKernels;
1078 if (Variables.
empty() || Kernels.empty())
1080 const size_t NumberVariables = Variables.
size();
1081 const size_t NumberKernels = Kernels.size();
1088 std::vector<Constant *> overallConstantExprElts(NumberKernels);
1089 for (
size_t i = 0; i < NumberKernels; i++) {
1091 overallConstantExprElts[i] =
1092 getAddressesOfVariablesInKernel(Func, Variables);
1105void AMDGPUSwLowerLDS::lowerNonKernelLDSAccesses(
1107 NonKernelLDSParameters &NKLDSParams) {
1110 LLVM_DEBUG(
dbgs() <<
"Sw LDS lowering, lower non-kernel access for : "
1111 << Func->getName());
1112 auto InsertAt = Func->getEntryBlock().getFirstNonPHIOrDbgOrAlloca();
1117 getLDSMemoryInstructions(Func, LDSInstructions);
1119 auto *KernelId = IRB.
CreateIntrinsic(Intrinsic::amdgcn_lds_kernel_id, {});
1122 auto &OrdereLDSGlobals = NKLDSParams.OrdereLDSGlobals;
1124 LDSBaseTable->
getValueType(), LDSBaseTable, {IRB.getInt32(0), KernelId});
1127 Value *LoadMallocPtr =
1131 const auto *GVIt =
llvm::find(OrdereLDSGlobals, GV);
1132 assert(GVIt != OrdereLDSGlobals.end());
1133 uint32_t GVOffset = std::distance(OrdereLDSGlobals.begin(), GVIt);
1137 {IRB.getInt32(0), KernelId, IRB.getInt32(GVOffset)});
1141 Value *BasePlusOffset =
1143 LLVM_DEBUG(
dbgs() <<
"Sw LDS Lowering, Replace non-kernel LDS for "
1145 replacesUsesOfGlobalInFunction(Func, GV, BasePlusOffset);
1147 translateLDSMemoryOperationsToGlobalMemory(Func, LoadMallocPtr,
1151static void reorderStaticDynamicIndirectLDSSet(KernelLDSParameters &LDSParams) {
1154 auto &DirectAccess = LDSParams.DirectAccess;
1155 auto &IndirectAccess = LDSParams.IndirectAccess;
1156 LDSParams.DirectAccess.StaticLDSGlobals = sortByName(
1157 std::vector<GlobalVariable *>(DirectAccess.StaticLDSGlobals.begin(),
1158 DirectAccess.StaticLDSGlobals.end()));
1159 LDSParams.DirectAccess.DynamicLDSGlobals = sortByName(
1160 std::vector<GlobalVariable *>(DirectAccess.DynamicLDSGlobals.begin(),
1161 DirectAccess.DynamicLDSGlobals.end()));
1162 LDSParams.IndirectAccess.StaticLDSGlobals = sortByName(
1163 std::vector<GlobalVariable *>(IndirectAccess.StaticLDSGlobals.begin(),
1164 IndirectAccess.StaticLDSGlobals.end()));
1165 LDSParams.IndirectAccess.DynamicLDSGlobals = sortByName(
1166 std::vector<GlobalVariable *>(IndirectAccess.DynamicLDSGlobals.begin(),
1167 IndirectAccess.DynamicLDSGlobals.end()));
1170void AMDGPUSwLowerLDS::initAsanInfo() {
1176 bool OrShadowOffset;
1178 &Scale, &OrShadowOffset);
1179 AsanInfo.Scale = Scale;
1180 AsanInfo.Offset =
Offset;
1184 for (
auto &
K : LDSAccesses) {
1188 if (
F->hasFnAttribute(Attribute::SanitizeAddress))
1194bool AMDGPUSwLowerLDS::run() {
1207 bool LowerAllLDS = hasFnWithSanitizeAddressAttr(LDSUsesInfo.
DirectAccess) ||
1215 bool DirectAccess) {
1216 for (
auto &
K : LDSAccesses) {
1218 if (!
F ||
K.second.empty())
1224 FuncLDSAccessInfo.KernelToLDSParametersMap.insert(
1225 {
F, KernelLDSParameters()});
1227 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[
F];
1229 FuncLDSAccessInfo.KernelsWithIndirectLDSAccess.
insert(
F);
1231 if (!DirectAccess) {
1233 LDSParams.IndirectAccess.DynamicLDSGlobals.insert(GV);
1235 LDSParams.IndirectAccess.StaticLDSGlobals.insert(GV);
1236 FuncLDSAccessInfo.AllNonKernelLDSAccess.insert(GV);
1239 LDSParams.DirectAccess.DynamicLDSGlobals.insert(GV);
1241 LDSParams.DirectAccess.StaticLDSGlobals.insert(GV);
1247 PopulateKernelStaticDynamicLDS(LDSUsesInfo.
DirectAccess,
true);
1248 PopulateKernelStaticDynamicLDS(LDSUsesInfo.
IndirectAccess,
false);
1253 for (
auto &
K : FuncLDSAccessInfo.KernelToLDSParametersMap) {
1255 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
1256 if (LDSParams.DirectAccess.StaticLDSGlobals.empty() &&
1257 LDSParams.DirectAccess.DynamicLDSGlobals.empty() &&
1258 LDSParams.IndirectAccess.StaticLDSGlobals.empty() &&
1259 LDSParams.IndirectAccess.DynamicLDSGlobals.empty())
1264 {
"amdgpu-no-workitem-id-x",
"amdgpu-no-workitem-id-y",
1265 "amdgpu-no-workitem-id-z",
"amdgpu-no-heap-ptr"});
1266 if (!LDSParams.IndirectAccess.StaticLDSGlobals.empty() ||
1267 !LDSParams.IndirectAccess.DynamicLDSGlobals.empty())
1269 reorderStaticDynamicIndirectLDSSet(LDSParams);
1270 buildSwLDSGlobal(Func);
1271 buildSwDynLDSGlobal(Func);
1272 populateSwMetadataGlobal(Func);
1273 populateSwLDSAttributeAndMetadata(Func);
1274 populateLDSToReplacementIndicesMap(Func);
1275 DomTreeUpdater DTU(DTCallback(*Func), DomTreeUpdater::UpdateStrategy::Lazy);
1276 lowerKernelLDSAccesses(Func, DTU);
1281 getUsesOfLDSByNonKernels();
1284 getNonKernelsWithLDSArguments(CG);
1287 if (!FuncLDSAccessInfo.NonKernelToLDSAccessMap.empty() ||
1288 !FuncLDSAccessInfo.NonKernelsWithLDSArgument.
empty()) {
1289 NonKernelLDSParameters NKLDSParams;
1290 NKLDSParams.OrderedKernels = getOrderedIndirectLDSAccessingKernels(
1291 FuncLDSAccessInfo.KernelsWithIndirectLDSAccess);
1292 NKLDSParams.OrdereLDSGlobals = getOrderedNonKernelAllLDSGlobals(
1293 FuncLDSAccessInfo.AllNonKernelLDSAccess);
1294 buildNonKernelLDSBaseTable(NKLDSParams);
1295 buildNonKernelLDSOffsetTable(NKLDSParams);
1296 for (
auto &
K : FuncLDSAccessInfo.NonKernelToLDSAccessMap) {
1300 std::vector<GlobalVariable *>(LDSGlobals.
begin(), LDSGlobals.
end()));
1301 lowerNonKernelLDSAccesses(Func, OrderedLDSGlobals, NKLDSParams);
1303 for (
Function *Func : FuncLDSAccessInfo.NonKernelsWithLDSArgument) {
1304 auto &
K = FuncLDSAccessInfo.NonKernelToLDSAccessMap;
1305 if (
K.contains(Func))
1308 lowerNonKernelLDSAccesses(Func, Vec, NKLDSParams);
1325 if (AsanInstrumentLDS) {
1332 for (
auto &Operand : OperandsToInstrument) {
1333 Value *Addr = Operand.getPtr();
1335 Operand.Alignment.valueOrOne(), Operand.TypeStoreSize,
1336 Operand.IsWrite,
nullptr,
false,
false, AsanInfo.Scale,
1345class AMDGPUSwLowerLDSLegacy :
public ModulePass {
1349 bool runOnModule(
Module &M)
override;
1356char AMDGPUSwLowerLDSLegacy::ID = 0;
1360 "AMDGPU Software lowering of LDS",
false,
false)
1365bool AMDGPUSwLowerLDSLegacy::runOnModule(
Module &M) {
1368 if (!M.getModuleFlag(
"nosanitize_address"))
1371 getAnalysisIfAvailable<DominatorTreeWrapperPass>();
1373 return DTW ? &DTW->getDomTree() : nullptr;
1376 AMDGPUSwLowerLDS SwLowerLDSImpl(M, DTCallback);
1377 bool IsChanged = SwLowerLDSImpl.run();
1382 return new AMDGPUSwLowerLDSLegacy();
1389 if (!M.getModuleFlag(
"nosanitize_address"))
1395 AMDGPUSwLowerLDS SwLowerLDSImpl(M, DTCallback);
1396 bool IsChanged = SwLowerLDSImpl.run();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file provides interfaces used to build and manipulate a call graph, which is a very useful tool ...
This file contains the declarations for the subclasses of Constant, which represent the different fla...
if(auto Err=PB.parsePassPipeline(MPM, Passes)) return wrap(std MPM run * Mod
FunctionAnalysisManager FAM
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
static DebugLoc getOrCreateDebugLoc(const Instruction *InsertBefore, DISubprogram *SP)
This class represents a conversion between pointers from one address space to another.
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 & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
This class represents any memset intrinsic.
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,...
void setVolatile(bool V)
Specify whether this is a volatile cmpxchg.
an instruction that atomically reads a memory location, combines it with another value,...
void setVolatile(bool V)
Specify whether this is a volatile RMW or not.
LLVM Basic Block Representation.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
A node in the call graph for a module.
Function * getFunction() const
Returns the function that this call graph node represents.
The basic data container for the call graph of a Module of IR.
This class represents a function call, abstracting a target machine's calling convention.
static LLVM_ABI Constant * get(ArrayType *T, ArrayRef< Constant * > V)
static Constant * getGetElementPtr(Type *Ty, Constant *C, ArrayRef< Constant * > IdxList, GEPNoWrapFlags NW=GEPNoWrapFlags::none(), std::optional< ConstantRange > InRange=std::nullopt, Type *OnlyIfReducedTy=nullptr)
Getelementptr form.
static LLVM_ABI Constant * get(StructType *T, ArrayRef< Constant * > V)
This is an important base class in LLVM.
LLVM_ABI void removeDeadConstantUsers() const
If there are any dead constant users dangling off of this constant, remove them.
Subprogram description. Uses SubclassData1.
A parsed version of the target data layout string in and methods for querying it.
Implements a dense probed hash-table based set.
Analysis pass which computes a DominatorTree.
static constexpr UpdateKind Insert
Legacy analysis pass which computes a DominatorTree.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
static GEPNoWrapFlags inBounds()
void applyUpdates(ArrayRef< UpdateT > Updates)
Submit updates to all available trees.
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set a particular kind of metadata attachment.
LLVM_ABI bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
LLVM_ABI void setSanitizerMetadata(SanitizerMetadata Meta)
@ InternalLinkage
Rename collisions when linking (static functions).
@ ExternalLinkage
Externally visible function.
Type * getValueType() const
MaybeAlign getAlign() const
Returns the alignment of the given variable.
LLVM_ABI void eraseFromParent()
eraseFromParent - This method unlinks 'this' from the containing module and deletes it.
ConstantInt * getInt1(bool V)
Get a constant value representing either true or false.
Value * CreateAddrSpaceCast(Value *V, Type *DestTy, const Twine &Name="", bool IsNonNull=false)
AtomicCmpXchgInst * CreateAtomicCmpXchg(Value *Ptr, Value *Cmp, Value *New, MaybeAlign Align, AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering, SyncScope::ID SSID=SyncScope::System)
IntegerType * getInt1Ty()
Fetch the type representing a single bit.
CondBrInst * CreateCondBr(Value *Cond, BasicBlock *True, BasicBlock *False, MDNode *BranchWeights=nullptr, MDNode *Unpredictable=nullptr)
Create a conditional 'br Cond, TrueDest, FalseDest' instruction.
Value * CreateIntToPtr(Value *V, Type *DestTy, const Twine &Name="")
void SetCurrentDebugLocation(const DebugLoc &L)
Set location information used by debugging information.
IntegerType * getInt32Ty()
Fetch the type representing a 32-bit integer.
IntegerType * getInt64Ty()
Fetch the type representing a 64-bit integer.
Value * CreateInBoundsGEP(Type *Ty, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &Name="")
LLVM_ABI CallInst * CreateElementUnorderedAtomicMemMove(Value *Dst, Align DstAlign, Value *Src, Align SrcAlign, Value *Size, uint32_t ElementSize, const AAMDNodes &AAInfo=AAMDNodes())
Create and insert an element unordered-atomic memmove between the specified pointers.
Value * CreateUDiv(Value *LHS, Value *RHS, const Twine &Name="", bool isExact=false)
ConstantInt * getInt64(uint64_t C)
Get a constant 64-bit value.
UncondBrInst * CreateBr(BasicBlock *Dest)
Create an unconditional 'br label X' instruction.
ConstantInt * getInt32(uint32_t C)
Get a constant 32-bit value.
PHINode * CreatePHI(Type *Ty, unsigned NumReservedValues, const Twine &Name="")
Value * CreateICmpEQ(Value *LHS, Value *RHS, const Twine &Name="")
LoadInst * CreateLoad(Type *Ty, Value *Ptr, const char *Name)
Provided to resolve 'CreateLoad(Ty, Ptr, "...")' correctly, instead of converting the string to 'bool...
CallInst * CreateElementUnorderedAtomicMemSet(Value *Ptr, Value *Val, uint64_t Size, Align Alignment, uint32_t ElementSize, const AAMDNodes &AAInfo=AAMDNodes())
Create and insert an element unordered-atomic memset of the region of memory starting at the given po...
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.
Value * CreateZExt(Value *V, Type *DestTy, const Twine &Name="", bool IsNonNeg=false)
ReturnInst * CreateRetVoid()
Create a 'ret void' instruction.
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.
StoreInst * CreateStore(Value *Val, Value *Ptr, bool isVolatile=false)
Value * CreateAdd(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Value * CreatePtrToInt(Value *V, Type *DestTy, const Twine &Name="")
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)
PointerType * getPtrTy(unsigned AddrSpace=0)
Fetch the type representing a pointer.
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
Type * getVoidTy()
Fetch the type representing void.
LLVM_ABI CallInst * CreateElementUnorderedAtomicMemCpy(Value *Dst, Align DstAlign, Value *Src, Align SrcAlign, Value *Size, uint32_t ElementSize, const AAMDNodes &AAInfo=AAMDNodes())
Create and insert an element unordered-atomic memcpy between the specified pointers.
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 * CreateOr(Value *LHS, Value *RHS, const Twine &Name="", bool IsDisjoint=false)
IntegerType * getInt8Ty()
Fetch the type representing an 8-bit integer.
Value * CreateMul(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
AtomicRMWInst * CreateAtomicRMW(AtomicRMWInst::BinOp Op, Value *Ptr, Value *Val, MaybeAlign Align, AtomicOrdering Ordering, SyncScope::ID SSID=SyncScope::System, bool Elementwise=false)
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
This is an important class for using LLVM in a threaded context.
An instruction for reading from memory.
LLVM_ABI MDNode * createRange(const APInt &Lo, const APInt &Hi)
Return metadata describing the range [Lo, Hi).
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
A Module instance is used to store all the information related to an LLVM module.
A container for an operand bundle being viewed as a set of values rather than a set of uses.
void addIncoming(Value *V, BasicBlock *BB)
Add an incoming value to the end of the PHI list.
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 & preserve()
Mark an analysis as preserved.
Return a value (possibly void), from a function.
A vector that has set insertion semantics.
size_type size() const
Determine the number of elements in the SetVector.
iterator end()
Get an iterator to the end of the SetVector.
void clear()
Completely clear the SetVector.
bool empty() const
Determine if the SetVector is empty or not.
iterator begin()
Get an iterator to the beginning of the SetVector.
bool insert(const value_type &X)
Insert a new element into the SetVector.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
Represent a constant reference to a string, i.e.
Class to represent struct types.
static LLVM_ABI StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
Target-Independent Code Generator Pass Configuration Options.
The instances of the Type class are immutable: once they are created, they are never changed.
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.
A Use represents the edge between a Value definition and its users.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this 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 void printAsOperand(raw_ostream &O, bool PrintType=true, const Module *M=nullptr) const
Print the name of this Value out to the specified raw_ostream.
LLVM_ABI bool replaceUsesWithIf(Value *New, llvm::function_ref< bool(Use &U)> ShouldReplace)
Go through the uses list for this definition and make each use point to "V" if the callback ShouldRep...
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
static LLVM_ABI VectorType * get(Type *ElementType, ElementCount EC)
This static method is the primary way to construct an VectorType.
An efficient, type-erasing, non-owning reference to a callable.
A raw_ostream that writes to an std::string.
A raw_ostream that writes to an SmallVector or SmallString.
StringRef str() const
Return a StringRef for the vector contents.
@ LOCAL_ADDRESS
Address space for local memory.
@ FLAT_ADDRESS
Address space for flat memory.
@ GLOBAL_ADDRESS
Address space for global memory (RAT0, VTX0).
GVUsesInfoTy getTransitiveUsesOfLDSForLowering(const CallGraph &CG, Module &M)
Collects all uses of LDS Global Variables in M using getUsesOfGVByFunction, with isLDSVariableToLower...
void getInterestingMemoryOperands(Module &M, Instruction *I, SmallVectorImpl< InterestingMemoryOperand > &Interesting)
Get all the memory operands from the instruction that needs to be instrumented.
bool isDynamicLDS(const GlobalVariable &GV)
unsigned getAMDHSACodeObjectVersion(const Module &M)
void removeFnAttrFromReachable(CallGraph &CG, Function *KernelRoot, ArrayRef< StringRef > FnAttrs)
Strip FnAttr attribute from any functions where we may have introduced its use.
bool eliminateGVConstantExprUsesFromAllInstructions(Module &M, function_ref< bool(const GlobalVariable &)> Filter)
Iterates over all GlobalVariables in M, and whenever Filter returns true, replace all constant users ...
LLVM_READNONE constexpr bool isKernel(CallingConv::ID CC)
DenseMap< Function *, DenseSet< GlobalVariable * > > FunctionVariableMap
bool isLDSVariableToLower(const GlobalVariable &GV)
Align getAlign(const DataLayout &DL, const GlobalVariable *GV)
void instrumentAddress(Module &M, IRBuilder<> &IRB, Instruction *OrigIns, Instruction *InsertBefore, Value *Addr, Align Alignment, TypeSize TypeStoreSize, bool IsWrite, Value *SizeArgument, bool UseCalls, bool Recover, int AsanScale, int AsanOffset)
Instrument the memory operand Addr.
uint64_t getRedzoneSizeForGlobal(int AsanScale, uint64_t SizeInBytes)
Given SizeInBytes of the Value to be instrunmented, Returns the redzone size corresponding to it.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
ModulePass * createAMDGPUSwLowerLDSLegacyPass()
auto find(R &&Range, const T &Val)
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
constexpr from_range_t from_range
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
char & AMDGPUSwLowerLDSLegacyPassID
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
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...
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
LLVM_ABI void getAddressSanitizerParams(const Triple &TargetTriple, int LongSize, bool IsKasan, uint64_t *ShadowBase, int *MappingScale, bool *OrShadowOffset)
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
FunctionVariableMap DirectAccess
FunctionVariableMap IndirectAccess
This struct is a compact representation of a valid (non-zero power of two) alignment.
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.
Align valueOrOne() const
For convenience, returns a valid alignment or 1 if undefined.