51#include "llvm/IR/IntrinsicsAMDGPU.h"
52#include "llvm/IR/IntrinsicsNVPTX.h"
74#define DEBUG_TYPE "openmp-opt"
77 "openmp-opt-disable",
cl::desc(
"Disable OpenMP specific optimizations."),
81 "openmp-opt-enable-merging",
87 cl::desc(
"Disable function internalization."),
98 "openmp-hide-memory-transfer-latency",
99 cl::desc(
"[WIP] Tries to hide the latency of host to device memory"
104 "openmp-opt-disable-deglobalization",
105 cl::desc(
"Disable OpenMP optimizations involving deglobalization."),
109 "openmp-opt-disable-spmdization",
110 cl::desc(
"Disable OpenMP optimizations involving SPMD-ization."),
114 "openmp-opt-disable-folding",
119 "openmp-opt-disable-state-machine-rewrite",
120 cl::desc(
"Disable OpenMP optimizations that replace the state machine."),
124 "openmp-opt-disable-barrier-elimination",
125 cl::desc(
"Disable OpenMP optimizations that eliminate barriers."),
129 "openmp-opt-print-module-after",
130 cl::desc(
"Print the current module after OpenMP optimizations."),
134 "openmp-opt-print-module-before",
135 cl::desc(
"Print the current module before OpenMP optimizations."),
139 "openmp-opt-inline-device",
150 cl::desc(
"Maximal number of attributor iterations."),
155 cl::desc(
"Maximum amount of shared memory to use."),
156 cl::init(std::numeric_limits<unsigned>::max()));
159 "openmp-opt-max-callees-for-specialization",
cl::Hidden,
160 cl::desc(
"Number of possible callees above which an indirect call site is "
161 "left alone rather than specialized into an if-cascade."),
165 "Number of OpenMP runtime calls deduplicated");
167 "Number of OpenMP parallel regions deleted");
169 "Number of OpenMP runtime functions identified");
171 "Number of OpenMP runtime function uses identified");
173 "Number of OpenMP target region entry points (=kernels) identified");
175 "Number of non-OpenMP target region kernels identified");
177 "Number of OpenMP target region entry points (=kernels) executed in "
178 "SPMD-mode instead of generic-mode");
179STATISTIC(NumOpenMPTargetRegionKernelsWithoutStateMachine,
180 "Number of OpenMP target region entry points (=kernels) executed in "
181 "generic-mode without a state machines");
182STATISTIC(NumOpenMPTargetRegionKernelsCustomStateMachineWithFallback,
183 "Number of OpenMP target region entry points (=kernels) executed in "
184 "generic-mode with customized state machines with fallback");
185STATISTIC(NumOpenMPTargetRegionKernelsCustomStateMachineWithoutFallback,
186 "Number of OpenMP target region entry points (=kernels) executed in "
187 "generic-mode with customized state machines without fallback");
189 NumOpenMPParallelRegionsReplacedInGPUStateMachine,
190 "Number of OpenMP parallel regions replaced with ID in GPU state machines");
192 "Number of OpenMP parallel regions merged");
194 "Amount of memory pushed to shared memory");
195STATISTIC(NumBarriersEliminated,
"Number of redundant barriers eliminated");
223#define KERNEL_ENVIRONMENT_IDX(MEMBER, IDX) \
224 constexpr unsigned MEMBER##Idx = IDX;
229#undef KERNEL_ENVIRONMENT_IDX
231#define KERNEL_ENVIRONMENT_CONFIGURATION_IDX(MEMBER, IDX) \
232 constexpr unsigned MEMBER##Idx = IDX;
242#undef KERNEL_ENVIRONMENT_CONFIGURATION_IDX
244#define KERNEL_ENVIRONMENT_GETTER(MEMBER, RETURNTYPE) \
245 RETURNTYPE *get##MEMBER##FromKernelEnvironment(ConstantStruct *KernelEnvC) { \
246 return cast<RETURNTYPE>(KernelEnvC->getAggregateElement(MEMBER##Idx)); \
252#undef KERNEL_ENVIRONMENT_GETTER
254#define KERNEL_ENVIRONMENT_CONFIGURATION_GETTER(MEMBER) \
255 ConstantInt *get##MEMBER##FromKernelEnvironment( \
256 ConstantStruct *KernelEnvC) { \
257 ConstantStruct *ConfigC = \
258 getConfigurationFromKernelEnvironment(KernelEnvC); \
259 return dyn_cast<ConstantInt>(ConfigC->getAggregateElement(MEMBER##Idx)); \
270#undef KERNEL_ENVIRONMENT_CONFIGURATION_GETTER
274 constexpr int InitKernelEnvironmentArgNo = 0;
289struct AAHeapToShared;
296 OMPInformationCache(
Module &M, AnalysisGetter &AG,
300 OpenMPPostLink(OpenMPPostLink) {
303 const Triple
T(OMPBuilder.M.getTargetTriple());
304 switch (
T.getArch()) {
308 assert(OMPBuilder.Config.IsTargetDevice &&
309 "OpenMP AMDGPU/NVPTX is only prepared to deal with device code.");
310 OMPBuilder.Config.IsGPU =
true;
313 OMPBuilder.Config.IsGPU =
false;
316 OMPBuilder.initialize();
317 initializeRuntimeFunctions(M);
318 initializeInternalControlVars();
322 struct InternalControlVarInfo {
330 StringRef EnvVarName;
336 ConstantInt *InitValue;
349 struct RuntimeFunctionInfo {
370 using UseVector = SmallVector<Use *, 16>;
373 void clearUsesMap() { UsesMap.clear(); }
376 operator bool()
const {
return Declaration; }
379 UseVector &getOrCreateUseVector(
Function *
F) {
380 std::shared_ptr<UseVector> &UV = UsesMap[
F];
382 UV = std::make_shared<UseVector>();
388 const UseVector *getUseVector(
Function &
F)
const {
389 auto I = UsesMap.find(&
F);
390 if (
I != UsesMap.end())
391 return I->second.get();
396 size_t getNumFunctionsWithUses()
const {
return UsesMap.size(); }
400 size_t getNumArgs()
const {
return ArgumentTypes.size(); }
405 void foreachUse(SmallVectorImpl<Function *> &SCC,
406 function_ref<
bool(Use &,
Function &)> CB) {
414 SmallVector<unsigned, 8> ToBeDeleted;
418 UseVector &UV = getOrCreateUseVector(
F);
428 while (!ToBeDeleted.
empty()) {
438 DenseMap<Function *, std::shared_ptr<UseVector>> UsesMap;
442 decltype(UsesMap)::iterator
begin() {
return UsesMap.begin(); }
443 decltype(UsesMap)::iterator
end() {
return UsesMap.end(); }
447 OpenMPIRBuilder OMPBuilder;
451 RuntimeFunction::OMPRTL___last>
455 DenseMap<Function *, RuntimeFunction> RuntimeFunctionIDMap;
459 InternalControlVar::ICV___last>
464 void initializeInternalControlVars() {
465#define ICV_RT_SET(_Name, RTL) \
467 auto &ICV = ICVs[_Name]; \
470#define ICV_RT_GET(Name, RTL) \
472 auto &ICV = ICVs[Name]; \
475#define ICV_DATA_ENV(Enum, _Name, _EnvVarName, Init) \
477 auto &ICV = ICVs[Enum]; \
480 ICV.InitKind = Init; \
481 ICV.EnvVarName = _EnvVarName; \
482 switch (ICV.InitKind) { \
483 case ICV_IMPLEMENTATION_DEFINED: \
484 ICV.InitValue = nullptr; \
487 ICV.InitValue = ConstantInt::get( \
488 Type::getInt32Ty(OMPBuilder.Int32->getContext()), 0); \
491 ICV.InitValue = ConstantInt::getFalse(OMPBuilder.Int1->getContext()); \
497#include "llvm/Frontend/OpenMP/OMPKinds.def"
503 static bool declMatchesRTFTypes(
Function *
F,
Type *RTFRetType,
510 if (
F->getReturnType() != RTFRetType)
512 if (
F->arg_size() != RTFArgTypes.
size())
515 auto *RTFTyIt = RTFArgTypes.
begin();
516 for (Argument &Arg :
F->args()) {
517 if (Arg.getType() != *RTFTyIt)
527 unsigned collectUses(RuntimeFunctionInfo &RFI,
bool CollectStats =
true) {
528 unsigned NumUses = 0;
529 if (!RFI.Declaration)
531 OMPBuilder.addAttributes(RFI.Kind, *RFI.Declaration);
534 NumOpenMPRuntimeFunctionsIdentified += 1;
535 NumOpenMPRuntimeFunctionUsesIdentified += RFI.Declaration->getNumUses();
539 for (Use &U : RFI.Declaration->uses()) {
541 if (!
CGSCC ||
CGSCC->empty() ||
CGSCC->contains(UserI->getFunction())) {
542 RFI.getOrCreateUseVector(UserI->getFunction()).push_back(&U);
546 RFI.getOrCreateUseVector(
nullptr).push_back(&U);
555 auto &RFI = RFIs[RTF];
557 collectUses(RFI,
false);
565 void setCallbackMetadata(
Function *
F,
unsigned ArgNo, ArrayRef<int> Indices,
567 if (!
F ||
F->hasMetadata(LLVMContext::MD_callback))
570 LLVMContext &Ctx =
F->getContext();
572 F->addMetadata(LLVMContext::MD_callback,
573 *
MDNode::get(Ctx, {MDB.createCallbackEncoding(ArgNo, Indices,
581 static Function *getAnalyzableCallback(
const CallBase &CB) {
585 MDNode *CallbackMD =
Callee->getMetadata(LLVMContext::MD_callback);
591 if (!Encoding || Encoding->getNumOperands() == 0)
602 if (!Callback ||
Callback->isDeclaration())
608 void recollectUses() {
609 for (
int Idx = 0;
Idx < RFIs.size(); ++
Idx)
614 void setCallingConvention(FunctionCallee Callee, CallInst *CI) {
629 RuntimeFunctionInfo &RFI = RFIs[Fn];
631 if (!RFI.Declaration || RFI.Declaration->isDeclaration())
639 void initializeRuntimeFunctions(
Module &M) {
642#define OMP_TYPE(VarName, ...) \
643 Type *VarName = OMPBuilder.VarName; \
646#define OMP_ARRAY_TYPE(VarName, ...) \
647 ArrayType *VarName##Ty = OMPBuilder.VarName##Ty; \
649 PointerType *VarName##PtrTy = OMPBuilder.VarName##PtrTy; \
650 (void)VarName##PtrTy;
652#define OMP_FUNCTION_TYPE(VarName, ...) \
653 FunctionType *VarName = OMPBuilder.VarName; \
655 PointerType *VarName##Ptr = OMPBuilder.VarName##Ptr; \
658#define OMP_STRUCT_TYPE(VarName, ...) \
659 StructType *VarName = OMPBuilder.VarName; \
661 PointerType *VarName##Ptr = OMPBuilder.VarName##Ptr; \
664#define OMP_RTL(_Enum, _Name, _IsVarArg, _ReturnType, ...) \
666 SmallVector<Type *, 8> ArgsTypes({__VA_ARGS__}); \
667 Function *F = M.getFunction(_Name); \
668 RTLFunctions.insert(F); \
669 if (declMatchesRTFTypes(F, OMPBuilder._ReturnType, ArgsTypes)) { \
670 RuntimeFunctionIDMap[F] = _Enum; \
671 auto &RFI = RFIs[_Enum]; \
674 RFI.IsVarArg = _IsVarArg; \
675 RFI.ReturnType = OMPBuilder._ReturnType; \
676 RFI.ArgumentTypes = std::move(ArgsTypes); \
677 RFI.Declaration = F; \
678 unsigned NumUses = collectUses(RFI); \
681 dbgs() << TAG << RFI.Name << (RFI.Declaration ? "" : " not") \
683 if (RFI.Declaration) \
684 dbgs() << TAG << "-> got " << NumUses << " uses in " \
685 << RFI.getNumFunctionsWithUses() \
686 << " different functions.\n"; \
691#define OMP_RTL_CB_INFO(_Enum, _Name, _ArgNo, _ArgIndices, _IsVarArg) \
692 setCallbackMetadata(M.getFunction(_Name), _ArgNo, _ArgIndices, _IsVarArg);
694#include "llvm/Frontend/OpenMP/OMPKinds.def"
700 for (StringRef Prefix : {
"__kmpc",
"_ZN4ompx",
"omp_"})
701 if (
F.hasFnAttribute(Attribute::NoInline) &&
702 F.getName().starts_with(Prefix) &&
703 !
F.hasFnAttribute(Attribute::OptimizeNone))
704 F.removeFnAttr(Attribute::NoInline);
712 DenseSet<const Function *> RTLFunctions;
715 bool OpenMPPostLink =
false;
722 SmallPtrSet<Function *, 8> SPMDizedKernels;
725template <
typename Ty,
bool InsertInval
idates = true>
727 bool contains(
const Ty &Elem)
const {
return Set.contains(Elem); }
728 bool insert(
const Ty &Elem) {
729 if (InsertInvalidates)
730 BooleanState::indicatePessimisticFixpoint();
731 return Set.insert(Elem);
734 const Ty &operator[](
int Idx)
const {
return Set[
Idx]; }
735 bool operator==(
const BooleanStateWithSetVector &
RHS)
const {
736 return BooleanState::operator==(
RHS) && Set ==
RHS.Set;
738 bool operator!=(
const BooleanStateWithSetVector &
RHS)
const {
739 return !(*
this ==
RHS);
742 bool empty()
const {
return Set.empty(); }
743 size_t size()
const {
return Set.size(); }
746 BooleanStateWithSetVector &
operator^=(
const BooleanStateWithSetVector &
RHS) {
747 BooleanState::operator^=(
RHS);
748 Set.insert_range(
RHS.Set);
757 typename decltype(Set)::iterator
begin() {
return Set.begin(); }
758 typename decltype(Set)::iterator
end() {
return Set.end(); }
759 typename decltype(Set)::const_iterator
begin()
const {
return Set.begin(); }
760 typename decltype(Set)::const_iterator
end()
const {
return Set.end(); }
763template <
typename Ty,
bool InsertInval
idates = true>
764using BooleanStateWithPtrSetVector =
765 BooleanStateWithSetVector<Ty *, InsertInvalidates>;
769 bool IsAtFixpoint =
false;
773 BooleanStateWithPtrSetVector<CallBase,
false>
774 ReachedKnownParallelRegions;
777 BooleanStateWithPtrSetVector<CallBase> ReachedUnknownParallelRegions;
782 BooleanStateWithPtrSetVector<Instruction, false> SPMDCompatibilityTracker;
786 CallBase *KernelInitCB =
nullptr;
790 ConstantStruct *KernelEnvC =
nullptr;
794 CallBase *KernelDeinitCB =
nullptr;
797 bool IsKernelEntry =
false;
800 BooleanStateWithPtrSetVector<Function, false> ReachingKernelEntries;
805 BooleanStateWithSetVector<uint8_t> ParallelLevels;
808 bool NestedParallelism =
false;
813 KernelInfoState() =
default;
814 KernelInfoState(
bool BestState) {
816 indicatePessimisticFixpoint();
820 bool isValidState()
const override {
return true; }
823 bool isAtFixpoint()
const override {
return IsAtFixpoint; }
828 ParallelLevels.indicatePessimisticFixpoint();
829 ReachingKernelEntries.indicatePessimisticFixpoint();
830 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
831 ReachedKnownParallelRegions.indicatePessimisticFixpoint();
832 ReachedUnknownParallelRegions.indicatePessimisticFixpoint();
833 NestedParallelism =
true;
834 return ChangeStatus::CHANGED;
840 ParallelLevels.indicateOptimisticFixpoint();
841 ReachingKernelEntries.indicateOptimisticFixpoint();
842 SPMDCompatibilityTracker.indicateOptimisticFixpoint();
843 ReachedKnownParallelRegions.indicateOptimisticFixpoint();
844 ReachedUnknownParallelRegions.indicateOptimisticFixpoint();
845 return ChangeStatus::UNCHANGED;
849 KernelInfoState &getAssumed() {
return *
this; }
850 const KernelInfoState &getAssumed()
const {
return *
this; }
853 if (SPMDCompatibilityTracker !=
RHS.SPMDCompatibilityTracker)
855 if (ReachedKnownParallelRegions !=
RHS.ReachedKnownParallelRegions)
857 if (ReachedUnknownParallelRegions !=
RHS.ReachedUnknownParallelRegions)
859 if (ReachingKernelEntries !=
RHS.ReachingKernelEntries)
861 if (ParallelLevels !=
RHS.ParallelLevels)
863 if (NestedParallelism !=
RHS.NestedParallelism)
869 bool mayContainParallelRegion() {
870 return !ReachedKnownParallelRegions.empty() ||
871 !ReachedUnknownParallelRegions.empty();
875 static KernelInfoState getBestState() {
return KernelInfoState(
true); }
877 static KernelInfoState getBestState(KernelInfoState &KIS) {
878 return getBestState();
882 static KernelInfoState getWorstState() {
return KernelInfoState(
false); }
885 KernelInfoState
operator^=(
const KernelInfoState &KIS) {
887 if (KIS.KernelInitCB) {
888 if (KernelInitCB && KernelInitCB != KIS.KernelInitCB)
891 KernelInitCB = KIS.KernelInitCB;
893 if (KIS.KernelDeinitCB) {
894 if (KernelDeinitCB && KernelDeinitCB != KIS.KernelDeinitCB)
897 KernelDeinitCB = KIS.KernelDeinitCB;
899 if (KIS.KernelEnvC) {
900 if (KernelEnvC && KernelEnvC != KIS.KernelEnvC)
903 KernelEnvC = KIS.KernelEnvC;
905 SPMDCompatibilityTracker ^= KIS.SPMDCompatibilityTracker;
906 ReachedKnownParallelRegions ^= KIS.ReachedKnownParallelRegions;
907 ReachedUnknownParallelRegions ^= KIS.ReachedUnknownParallelRegions;
908 NestedParallelism |= KIS.NestedParallelism;
912 KernelInfoState
operator&=(
const KernelInfoState &KIS) {
913 return (*
this ^= KIS);
923 AllocaInst *Array =
nullptr;
925 SmallVector<Value *, 8> StoredValues;
927 SmallVector<StoreInst *, 8> LastAccesses;
929 OffloadArray() =
default;
935 bool initialize(AllocaInst &Array, Instruction &Before) {
936 if (!getValues(Array, Before))
939 this->Array = &Array;
943 static const unsigned DeviceIDArgNum = 1;
944 static const unsigned BasePtrsArgNum = 3;
945 static const unsigned PtrsArgNum = 4;
946 static const unsigned SizesArgNum = 5;
952 bool getValues(AllocaInst &Array, Instruction &Before) {
954 const DataLayout &
DL = Array.getDataLayout();
955 std::optional<TypeSize> ArraySize = Array.getAllocationSize(
DL);
956 if (!ArraySize || !ArraySize->isFixed())
960 StoredValues.assign(NumValues,
nullptr);
961 LastAccesses.assign(NumValues,
nullptr);
969 for (Instruction &
I : *BB) {
985 LastAccesses[
Idx] = S;
996 const unsigned NumValues = StoredValues.size();
997 for (
unsigned I = 0;
I < NumValues; ++
I) {
998 if (!StoredValues[
I] || !LastAccesses[
I])
1009static std::optional<uint64_t>
1011 unsigned CallbackOpNo) {
1012 std::optional<uint64_t> EntryCount;
1018 if (std::optional<uint64_t> EC =
Callback->getEntryCount())
1021 EntryCount = EntryCount ? std::max(*EntryCount, *EC) : *
EC;
1026static bool moduleHasSampleProfile(
const Module &M) {
1027 std::unique_ptr<ProfileSummary> Summary(
1034 using OptimizationRemarkGetter =
1035 function_ref<OptimizationRemarkEmitter &(
Function *)>;
1037 OpenMPOpt(SmallVectorImpl<Function *> &SCC, CallGraphUpdater &CGUpdater,
1038 OptimizationRemarkGetter OREGetter,
1039 OMPInformationCache &OMPInfoCache, Attributor &A)
1040 : M(*(*SCC.
begin())->
getParent()), SCC(SCC), CGUpdater(CGUpdater),
1041 OREGetter(OREGetter), OMPInfoCache(OMPInfoCache), A(A) {}
1044 bool remarksEnabled() {
1045 auto &Ctx = M.getContext();
1050 bool run(
bool IsModulePass) {
1060 Changed |= runAttributor(IsModulePass);
1063 OMPInfoCache.recollectUses();
1066 Changed |= rewriteDeviceCodeStateMachine();
1072 Changed |= removeSPMDParallelWrappers();
1074 if (remarksEnabled())
1075 analysisGlobalization();
1082 Changed |= runAttributor(IsModulePass);
1085 OMPInfoCache.recollectUses();
1087 Changed |= deleteParallelRegions();
1090 Changed |= hideMemTransfersLatency();
1091 Changed |= deduplicateRuntimeCalls();
1093 if (mergeParallelRegions()) {
1094 deduplicateRuntimeCalls();
1100 if (OMPInfoCache.OpenMPPostLink)
1101 Changed |= removeRuntimeSymbols();
1108 void printICVs()
const {
1113 for (
auto ICV : ICVs) {
1114 auto ICVInfo = OMPInfoCache.ICVs[ICV];
1115 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
1116 return ORA <<
"OpenMP ICV " <<
ore::NV(
"OpenMPICV", ICVInfo.Name)
1118 << (ICVInfo.InitValue
1119 ?
toString(ICVInfo.InitValue->getValue(), 10,
true)
1120 :
"IMPLEMENTATION_DEFINED");
1129 void printKernels()
const {
1134 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
1135 return ORA <<
"OpenMP GPU kernel "
1136 <<
ore::NV(
"OpenMPGPUKernel",
F->getName()) <<
"\n";
1145 static CallInst *getCallIfRegularCall(
1146 Use &U, OMPInformationCache::RuntimeFunctionInfo *RFI =
nullptr) {
1157 static CallInst *getCallIfRegularCall(
1158 Value &V, OMPInformationCache::RuntimeFunctionInfo *RFI =
nullptr) {
1169 bool mergeParallelRegions() {
1170 const unsigned CallbackCalleeOperand = 2;
1171 const unsigned CallbackFirstArgOperand = 3;
1175 OMPInformationCache::RuntimeFunctionInfo &RFI =
1176 OMPInfoCache.RFIs[OMPRTL___kmpc_fork_call];
1178 if (!RFI.Declaration)
1182 OMPInformationCache::RuntimeFunctionInfo UnmergableCallsInfo[] = {
1183 OMPInfoCache.RFIs[OMPRTL___kmpc_push_proc_bind],
1184 OMPInfoCache.RFIs[OMPRTL___kmpc_push_num_threads],
1188 LoopInfo *LI =
nullptr;
1189 DominatorTree *DT =
nullptr;
1191 SmallDenseMap<BasicBlock *, SmallPtrSet<Instruction *, 4>> BB2PRMap;
1193 BasicBlock *StartBB =
nullptr, *EndBB =
nullptr;
1194 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
1196 BasicBlock *CGStartBB = CodeGenIP.getNodeParent();
1198 assert(StartBB !=
nullptr &&
"StartBB should not be null");
1200 assert(EndBB !=
nullptr &&
"EndBB should not be null");
1201 EndBB->getTerminator()->setSuccessor(0, CGEndBB);
1205 auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
Value &,
1206 Value &Inner,
Value *&ReplacementValue) -> InsertPointTy {
1207 ReplacementValue = &Inner;
1211 auto FiniCB = [&](InsertPointTy CodeGenIP) {
return Error::success(); };
1215 auto CreateSequentialRegion = [&](
Function *OuterFn,
1221 BasicBlock *ParentBB = SeqStartI->getParent();
1223 SplitBlock(ParentBB, SeqEndI->getNextNode(), DT, LI);
1227 SplitBlock(ParentBB, SeqStartI, DT, LI,
nullptr,
"seq.par.merged");
1230 "Expected a different CFG");
1234 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
1236 BasicBlock *CGStartBB = CodeGenIP.getNodeParent();
1238 assert(SeqStartBB !=
nullptr &&
"SeqStartBB should not be null");
1240 assert(SeqEndBB !=
nullptr &&
"SeqEndBB should not be null");
1244 auto FiniCB = [&](InsertPointTy CodeGenIP) {
return Error::success(); };
1248 for (Instruction &
I : *SeqStartBB) {
1249 SmallPtrSet<Instruction *, 4> OutsideUsers;
1250 for (User *Usr :
I.users()) {
1258 OutsideUsers.
insert(&UsrI);
1261 if (OutsideUsers.
empty())
1266 const DataLayout &
DL = M.getDataLayout();
1267 AllocaInst *AllocaI =
new AllocaInst(
1268 I.getType(),
DL.getAllocaAddrSpace(),
nullptr,
1273 new StoreInst(&
I, AllocaI, SeqStartBB->getTerminator()->getIterator());
1277 for (Instruction *UsrI : OutsideUsers) {
1278 LoadInst *LoadI =
new LoadInst(
I.getType(), AllocaI,
1279 I.getName() +
".seq.output.load",
1285 OpenMPIRBuilder::LocationDescription Loc(ParentBB->
end(),
DL);
1287 OMPInfoCache.OMPBuilder.createMaster(Loc, BodyGenCB, FiniCB));
1288 cantFail(OMPInfoCache.OMPBuilder.createBarrier({SeqAfterIP, DL},
1304 auto Merge = [&](
const SmallVectorImpl<CallInst *> &MergableCIs,
1308 assert(MergableCIs.
size() > 1 &&
"Assumed multiple mergable CIs");
1310 auto Remark = [&](OptimizationRemark
OR) {
1311 OR <<
"Parallel region merged with parallel region"
1312 << (MergableCIs.
size() > 2 ?
"s" :
"") <<
" at ";
1315 if (CI != MergableCIs.
back())
1323 Function *OriginalFn = BB->getParent();
1325 <<
" parallel regions in " << OriginalFn->
getName()
1329 EndBB =
SplitBlock(BB, MergableCIs.
back()->getNextNode(), DT, LI);
1331 SplitBlock(EndBB, &*EndBB->getFirstInsertionPt(), DT, LI);
1335 assert(BB->getUniqueSuccessor() == StartBB &&
"Expected a different CFG");
1336 const DebugLoc DL = BB->getTerminator()->getDebugLoc();
1341 for (
auto *It = MergableCIs.
begin(), *
End = MergableCIs.
end() - 1;
1350 CreateSequentialRegion(OriginalFn, BB, ForkCI->
getNextNode(),
1354 OpenMPIRBuilder::LocationDescription Loc(BB->end(),
DL);
1355 IRBuilder<>::InsertPoint AllocaIP(
1360 cantFail(OMPInfoCache.OMPBuilder.createParallel(
1361 Loc, AllocaIP, {}, BodyGenCB, PrivCB, FiniCB,
1362 nullptr,
nullptr, OMP_PROC_BIND_default,
1367 OMPInfoCache.OMPBuilder.finalize(OriginalFn);
1370 std::optional<uint64_t> WrapperCount =
1371 getMergedWrapperEntryCount(MergableCIs, CallbackCalleeOperand);
1377 const bool SampleProfile =
1378 moduleHasSampleProfile(*OriginalFn->
getParent());
1382 SmallVector<Value *, 8>
Args;
1383 for (
auto *CI : MergableCIs) {
1385 FunctionType *FT = OMPInfoCache.OMPBuilder.ParallelTask;
1389 for (
unsigned U = CallbackFirstArgOperand,
E = CI->
arg_size(); U <
E;
1399 if (WrapperCount && SampleProfile) {
1405 for (
unsigned U = CallbackFirstArgOperand,
E = CI->
arg_size(); U <
E;
1409 U - (CallbackFirstArgOperand - CallbackCalleeOperand), A);
1412 if (CI != MergableCIs.back()) {
1415 cantFail(OMPInfoCache.OMPBuilder.createBarrier(
1416 {NewCI->getNextNode()->getIterator(), NewCI->getDebugLoc()},
1423 assert(OutlinedFn != OriginalFn &&
"Outlining failed");
1424 CGUpdater.registerOutlinedFunction(*OriginalFn, *OutlinedFn);
1425 CGUpdater.reanalyzeFunction(*OriginalFn);
1427 NumOpenMPParallelRegionsMerged += MergableCIs.size();
1435 CallInst *CI = getCallIfRegularCall(U, &RFI);
1442 RFI.foreachUse(SCC, DetectPRsCB);
1448 for (
auto &It : BB2PRMap) {
1449 auto &CIs = It.getSecond();
1464 auto IsMergable = [&](
Instruction &
I,
bool IsBeforeMergableRegion) {
1467 if (
I.isTerminator())
1474 if (IsBeforeMergableRegion) {
1476 if (!CalledFunction)
1483 for (
const auto &RFI : UnmergableCallsInfo) {
1484 if (CalledFunction == RFI.Declaration)
1503 if (CIs.count(&
I)) {
1509 if (IsMergable(
I, MergableCIs.
empty()))
1514 for (; It !=
End; ++It) {
1516 if (CIs.count(&SkipI)) {
1518 <<
" due to " <<
I <<
"\n");
1525 if (MergableCIs.
size() > 1) {
1526 MergableCIsVector.
push_back(MergableCIs);
1528 <<
" parallel regions in block " << BB->
getName()
1533 MergableCIs.
clear();
1536 if (!MergableCIsVector.
empty()) {
1539 for (
auto &MergableCIs : MergableCIsVector)
1540 Merge(MergableCIs, BB);
1541 MergableCIsVector.clear();
1548 OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_fork_call);
1549 OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_barrier);
1550 OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_master);
1551 OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_end_master);
1558 bool deleteParallelRegions() {
1559 const unsigned CallbackCalleeOperand = 2;
1561 OMPInformationCache::RuntimeFunctionInfo &RFI =
1562 OMPInfoCache.RFIs[OMPRTL___kmpc_fork_call];
1564 if (!RFI.Declaration)
1569 CallInst *CI = getCallIfRegularCall(U);
1576 if (!Fn->onlyReadsMemory())
1578 if (!Fn->hasFnAttribute(Attribute::WillReturn))
1584 auto Remark = [&](OptimizationRemark
OR) {
1585 return OR <<
"Removing parallel region with no side-effects.";
1591 ++NumOpenMPParallelRegionsDeleted;
1595 RFI.foreachUse(SCC, DeleteCallCB);
1601 bool deduplicateRuntimeCalls() {
1605 OMPRTL_omp_get_num_threads,
1606 OMPRTL_omp_in_parallel,
1607 OMPRTL_omp_get_cancellation,
1608 OMPRTL_omp_get_supported_active_levels,
1609 OMPRTL_omp_get_level,
1610 OMPRTL_omp_get_ancestor_thread_num,
1611 OMPRTL_omp_get_team_size,
1612 OMPRTL_omp_get_active_level,
1613 OMPRTL_omp_in_final,
1614 OMPRTL_omp_get_proc_bind,
1615 OMPRTL_omp_get_num_places,
1616 OMPRTL_omp_get_num_procs,
1617 OMPRTL_omp_get_place_num,
1618 OMPRTL_omp_get_partition_num_places,
1619 OMPRTL_omp_get_partition_place_nums};
1622 SmallSetVector<Value *, 16> GTIdArgs;
1623 collectGlobalThreadIdArguments(GTIdArgs);
1625 <<
" global thread ID arguments\n");
1628 for (
auto DeduplicableRuntimeCallID : DeduplicableRuntimeCallIDs)
1629 Changed |= deduplicateRuntimeCalls(
1630 *
F, OMPInfoCache.RFIs[DeduplicableRuntimeCallID]);
1634 Value *GTIdArg =
nullptr;
1635 for (Argument &Arg :
F->args())
1636 if (GTIdArgs.
count(&Arg)) {
1640 Changed |= deduplicateRuntimeCalls(
1641 *
F, OMPInfoCache.RFIs[OMPRTL___kmpc_global_thread_num], GTIdArg);
1648 bool removeRuntimeSymbols() {
1653 if (GlobalVariable *GV = M.getNamedGlobal(
"__llvm_rpc_client")) {
1654 if (GV->hasNUsesOrMore(1))
1658 GV->eraseFromParent();
1670 bool hideMemTransfersLatency() {
1671 auto &RFI = OMPInfoCache.RFIs[OMPRTL___tgt_target_data_begin_mapper];
1674 auto *RTCall = getCallIfRegularCall(U, &RFI);
1678 OffloadArray OffloadArrays[3];
1679 if (!getValuesInOffloadArrays(*RTCall, OffloadArrays))
1682 LLVM_DEBUG(dumpValuesInOffloadArrays(OffloadArrays));
1685 bool WasSplit =
false;
1686 Instruction *WaitMovementPoint = canBeMovedDownwards(*RTCall);
1687 if (WaitMovementPoint)
1688 WasSplit = splitTargetDataBeginRTC(*RTCall, *WaitMovementPoint);
1693 if (OMPInfoCache.runtimeFnsAvailable(
1694 {OMPRTL___tgt_target_data_begin_mapper_issue,
1695 OMPRTL___tgt_target_data_begin_mapper_wait}))
1696 RFI.foreachUse(SCC, SplitMemTransfers);
1701 void analysisGlobalization() {
1702 auto &RFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
1704 auto CheckGlobalization = [&](
Use &
U,
Function &Decl) {
1705 if (CallInst *CI = getCallIfRegularCall(U, &RFI)) {
1706 auto Remark = [&](OptimizationRemarkMissed ORM) {
1708 <<
"Found thread data sharing on the GPU. "
1709 <<
"Expect degraded performance due to data globalization.";
1717 RFI.foreachUse(SCC, CheckGlobalization);
1722 bool getValuesInOffloadArrays(CallInst &RuntimeCall,
1724 assert(OAs.
size() == 3 &&
"Need space for three offload arrays!");
1734 Value *BasePtrsArg =
1746 if (!OAs[0].
initialize(*BasePtrsArray, RuntimeCall))
1754 if (!OAs[1].
initialize(*PtrsArray, RuntimeCall))
1766 if (!OAs[2].
initialize(*SizesArray, RuntimeCall))
1777 assert(OAs.
size() == 3 &&
"There are three offload arrays to debug!");
1780 std::string ValuesStr;
1781 raw_string_ostream
Printer(ValuesStr);
1782 std::string Separator =
" --- ";
1784 for (
auto *BP : OAs[0].StoredValues) {
1788 LLVM_DEBUG(
dbgs() <<
"\t\toffload_baseptrs: " << ValuesStr <<
"\n");
1791 for (
auto *
P : OAs[1].StoredValues) {
1798 for (
auto *S : OAs[2].StoredValues) {
1802 LLVM_DEBUG(
dbgs() <<
"\t\toffload_sizes: " << ValuesStr <<
"\n");
1807 Instruction *canBeMovedDownwards(CallInst &RuntimeCall) {
1812 bool IsWorthIt =
false;
1831 return RuntimeCall.
getParent()->getTerminator();
1835 bool splitTargetDataBeginRTC(CallInst &RuntimeCall,
1836 Instruction &WaitMovementPoint) {
1840 auto &
IRBuilder = OMPInfoCache.OMPBuilder;
1843 IRBuilder.Builder.SetInsertPoint(
Entry.getFirstNonPHIOrAlloca());
1845 IRBuilder.AsyncInfo,
nullptr,
"handle");
1852 FunctionCallee IssueDecl =
IRBuilder.getOrCreateRuntimeFunction(
1853 M, OMPRTL___tgt_target_data_begin_mapper_issue);
1856 SmallVector<Value *, 16>
Args;
1857 for (
auto &Arg : RuntimeCall.
args())
1858 Args.push_back(Arg.get());
1859 Args.push_back(Handle);
1863 OMPInfoCache.setCallingConvention(IssueDecl, IssueCallsite);
1868 FunctionCallee WaitDecl =
IRBuilder.getOrCreateRuntimeFunction(
1869 M, OMPRTL___tgt_target_data_begin_mapper_wait);
1871 Value *WaitParams[2] = {
1873 OffloadArray::DeviceIDArgNum),
1877 WaitDecl, WaitParams,
"", WaitMovementPoint.
getIterator());
1878 OMPInfoCache.setCallingConvention(WaitDecl, WaitCallsite);
1883 static Value *combinedIdentStruct(
Value *CurrentIdent,
Value *NextIdent,
1884 bool GlobalOnly,
bool &SingleChoice) {
1885 if (CurrentIdent == NextIdent)
1886 return CurrentIdent;
1891 SingleChoice = !CurrentIdent;
1903 getCombinedIdentFromCallUsesIn(OMPInformationCache::RuntimeFunctionInfo &RFI,
1905 bool SingleChoice =
true;
1906 Value *Ident =
nullptr;
1908 CallInst *CI = getCallIfRegularCall(U, &RFI);
1909 if (!CI || &
F != &Caller)
1912 true, SingleChoice);
1915 RFI.foreachUse(SCC, CombineIdentStruct);
1917 if (!Ident || !SingleChoice) {
1921 if (!OMPInfoCache.OMPBuilder.getInsertionPoint().isValid())
1922 OMPInfoCache.OMPBuilder.updateToLocation(
1923 {
F.getEntryBlock().begin(),
DebugLoc()});
1926 uint32_t SrcLocStrSize;
1928 OMPInfoCache.OMPBuilder.getOrCreateDefaultSrcLocStr(SrcLocStrSize);
1929 Ident = OMPInfoCache.OMPBuilder.getOrCreateIdent(Loc, SrcLocStrSize);
1936 bool deduplicateRuntimeCalls(
Function &
F,
1937 OMPInformationCache::RuntimeFunctionInfo &RFI,
1938 Value *ReplVal =
nullptr) {
1939 auto *UV = RFI.getUseVector(
F);
1940 if (!UV || UV->size() + (ReplVal !=
nullptr) < 2)
1944 dbgs() <<
TAG <<
"Deduplicate " << UV->size() <<
" uses of " << RFI.Name
1945 << (ReplVal ?
" with an existing value\n" :
"\n") <<
"\n");
1949 "Unexpected replacement value!");
1952 auto CanBeMoved = [
this](CallBase &CB) {
1958 for (
unsigned U = 1;
U < NumArgs; ++
U)
1966 OMPInfoCache.getAnalysisResultForFunction<DominatorTreeAnalysis>(
F);
1970 for (Use *U : *UV) {
1971 if (CallInst *CI = getCallIfRegularCall(*U, &RFI)) {
1976 if (!CanBeMoved(*CI))
1984 assert(IP &&
"Expected insertion point!");
1994 Value *Ident = getCombinedIdentFromCallUsesIn(RFI,
F,
2002 CallInst *CI = getCallIfRegularCall(U, &RFI);
2003 if (!CI || CI == ReplVal || &
F != &Caller)
2007 auto Remark = [&](OptimizationRemark
OR) {
2008 return OR <<
"OpenMP runtime call "
2009 <<
ore::NV(
"OpenMPOptRuntime", RFI.Name) <<
" deduplicated.";
2018 ++NumOpenMPRuntimeCallsDeduplicated;
2022 RFI.foreachUse(SCC, ReplaceAndDeleteCB);
2028 void collectGlobalThreadIdArguments(SmallSetVector<Value *, 16> >IdArgs) {
2035 auto CallArgOpIsGTId = [&](
Function &
F,
unsigned ArgNo, CallInst &RefCI) {
2036 if (!
F.hasLocalLinkage())
2038 for (Use &U :
F.uses()) {
2039 if (CallInst *CI = getCallIfRegularCall(U)) {
2041 if (CI == &RefCI || GTIdArgs.
count(ArgOp) ||
2042 getCallIfRegularCall(
2043 *ArgOp, &OMPInfoCache.RFIs[OMPRTL___kmpc_global_thread_num]))
2052 auto AddUserArgs = [&](
Value >Id) {
2053 for (Use &U : GTId.uses())
2057 if (CallArgOpIsGTId(*Callee,
U.getOperandNo(), *CI))
2062 OMPInformationCache::RuntimeFunctionInfo &GlobThreadNumRFI =
2063 OMPInfoCache.RFIs[OMPRTL___kmpc_global_thread_num];
2065 GlobThreadNumRFI.foreachUse(SCC, [&](Use &U,
Function &
F) {
2066 if (CallInst *CI = getCallIfRegularCall(U, &GlobThreadNumRFI))
2074 for (
unsigned U = 0;
U < GTIdArgs.
size(); ++
U)
2075 AddUserArgs(*GTIdArgs[U]);
2083 DenseMap<Function *, std::optional<Kernel>> UniqueKernelMap;
2089 Kernel getUniqueKernelFor(Instruction &
I) {
2090 return getUniqueKernelFor(*
I.getFunction());
2095 bool rewriteDeviceCodeStateMachine();
2100 bool removeSPMDParallelWrappers();
2116 template <
typename RemarkKind,
typename RemarkCallBack>
2117 void emitRemark(Instruction *
I, StringRef RemarkName,
2118 RemarkCallBack &&RemarkCB)
const {
2120 auto &ORE = OREGetter(
F);
2124 return RemarkCB(RemarkKind(
DEBUG_TYPE, RemarkName,
I))
2125 <<
" [" << RemarkName <<
"]";
2129 [&]() {
return RemarkCB(RemarkKind(
DEBUG_TYPE, RemarkName,
I)); });
2133 template <
typename RemarkKind,
typename RemarkCallBack>
2135 RemarkCallBack &&RemarkCB)
const {
2136 auto &ORE = OREGetter(
F);
2140 return RemarkCB(RemarkKind(
DEBUG_TYPE, RemarkName,
F))
2141 <<
" [" << RemarkName <<
"]";
2145 [&]() {
return RemarkCB(RemarkKind(
DEBUG_TYPE, RemarkName,
F)); });
2152 SmallVectorImpl<Function *> &SCC;
2156 CallGraphUpdater &CGUpdater;
2159 OptimizationRemarkGetter OREGetter;
2162 OMPInformationCache &OMPInfoCache;
2168 bool runAttributor(
bool IsModulePass) {
2172 registerAAs(IsModulePass);
2177 <<
" functions, result: " <<
Changed <<
".\n");
2179 if (
Changed == ChangeStatus::CHANGED)
2180 OMPInfoCache.invalidateAnalyses();
2182 return Changed == ChangeStatus::CHANGED;
2189 void registerAAs(
bool IsModulePass);
2194 static void registerAAsForFunction(Attributor &A,
const Function &
F);
2198 if (OMPInfoCache.CGSCC && !OMPInfoCache.CGSCC->empty() &&
2199 !OMPInfoCache.CGSCC->contains(&
F))
2204 std::optional<Kernel> &CachedKernel = UniqueKernelMap[&
F];
2206 return *CachedKernel;
2213 return *CachedKernel;
2216 CachedKernel =
nullptr;
2217 if (!
F.hasLocalLinkage()) {
2220 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
2221 return ORA <<
"Potentially unknown OpenMP target region caller.";
2229 auto GetUniqueKernelForUse = [&](
const Use &
U) ->
Kernel {
2232 if (
Cmp->isEquality())
2233 return getUniqueKernelFor(*Cmp);
2239 return getUniqueKernelFor(*CB);
2241 OMPInformationCache::RuntimeFunctionInfo &KernelParallelRFI =
2242 OMPInfoCache.RFIs[OMPRTL___kmpc_parallel_60];
2244 if (OpenMPOpt::getCallIfRegularCall(*
U.getUser(), &KernelParallelRFI))
2245 return getUniqueKernelFor(*CB);
2253 SmallPtrSet<Kernel, 2> PotentialKernels;
2254 OMPInformationCache::foreachUse(
F, [&](
const Use &U) {
2255 PotentialKernels.
insert(GetUniqueKernelForUse(U));
2259 if (PotentialKernels.
size() == 1)
2260 K = *PotentialKernels.
begin();
2263 UniqueKernelMap[&
F] =
K;
2268bool OpenMPOpt::rewriteDeviceCodeStateMachine() {
2269 OMPInformationCache::RuntimeFunctionInfo &KernelParallelRFI =
2270 OMPInfoCache.RFIs[OMPRTL___kmpc_parallel_60];
2273 if (!KernelParallelRFI)
2284 bool UnknownUse =
false;
2285 bool KernelParallelUse =
false;
2286 unsigned NumDirectCalls = 0;
2289 OMPInformationCache::foreachUse(*
F, [&](Use &U) {
2297 ToBeReplacedStateMachineUses.
push_back(&U);
2303 OpenMPOpt::getCallIfRegularCall(*
U.getUser(), &KernelParallelRFI);
2304 const unsigned int WrapperFunctionArgNo = 6;
2305 if (!KernelParallelUse && CI &&
2307 KernelParallelUse =
true;
2308 ToBeReplacedStateMachineUses.
push_back(&U);
2316 if (!KernelParallelUse)
2322 if (UnknownUse || NumDirectCalls != 1 ||
2323 ToBeReplacedStateMachineUses.
size() > 2) {
2324 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
2325 return ORA <<
"Parallel region is used in "
2326 << (UnknownUse ?
"unknown" :
"unexpected")
2327 <<
" ways. Will not attempt to rewrite the state machine.";
2337 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
2338 return ORA <<
"Parallel region is not called from a unique kernel. "
2339 "Will not attempt to rewrite the state machine.";
2351 Type *Int8Ty = Type::getInt8Ty(
M.getContext());
2353 auto *
ID =
new GlobalVariable(
2357 for (Use *U : ToBeReplacedStateMachineUses)
2359 ID,
U->get()->getType()));
2361 ++NumOpenMPParallelRegionsReplacedInGPUStateMachine;
2369bool OpenMPOpt::removeSPMDParallelWrappers() {
2371 if (OMPInfoCache.SPMDizedKernels.empty())
2374 OMPInformationCache::RuntimeFunctionInfo &KernelParallelRFI =
2375 OMPInfoCache.RFIs[OMPRTL___kmpc_parallel_60];
2376 if (!KernelParallelRFI || !KernelParallelRFI.Declaration)
2379 constexpr unsigned WrapperFunctionArgNo = 6;
2381 for (User *U : KernelParallelRFI.Declaration->
users()) {
2384 CI->
arg_size() <= WrapperFunctionArgNo)
2398 if (!K || !OMPInfoCache.SPMDizedKernels.contains(K))
2402 WrapperFunctionArgNo,
2411struct AAICVTracker :
public StateWrapper<BooleanState, AbstractAttribute> {
2412 using Base = StateWrapper<BooleanState, AbstractAttribute>;
2413 AAICVTracker(
const IRPosition &IRP, Attributor &
A) :
Base(IRP) {}
2416 bool isAssumedTracked()
const {
return getAssumed(); }
2419 bool isKnownTracked()
const {
return getAssumed(); }
2422 static AAICVTracker &createForPosition(
const IRPosition &IRP, Attributor &
A);
2426 const Instruction *
I,
2427 Attributor &
A)
const {
2428 return std::nullopt;
2434 virtual std::optional<Value *>
2442 StringRef
getName()
const override {
return "AAICVTracker"; }
2445 const char *getIdAddr()
const override {
return &ID; }
2448 static bool classof(
const AbstractAttribute *AA) {
2452 static const char ID;
2455struct AAICVTrackerFunction :
public AAICVTracker {
2456 AAICVTrackerFunction(
const IRPosition &IRP, Attributor &
A)
2457 : AAICVTracker(IRP,
A) {}
2460 const std::string getAsStr(Attributor *)
const override {
2461 return "ICVTrackerFunction";
2465 void trackStatistics()
const override {}
2469 return ChangeStatus::UNCHANGED;
2474 InternalControlVar::ICV___last>
2475 ICVReplacementValuesMap;
2482 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
2485 auto &SetterRFI = OMPInfoCache.RFIs[OMPInfoCache.ICVs[ICV].Setter];
2487 auto &ValuesMap = ICVReplacementValuesMap[ICV];
2489 CallInst *CI = OpenMPOpt::getCallIfRegularCall(U);
2495 if (ValuesMap.insert(std::make_pair(CI, CI->
getArgOperand(0))).second)
2496 HasChanged = ChangeStatus::CHANGED;
2502 std::optional<Value *> ReplVal = getValueForCall(
A,
I, ICV);
2503 if (ReplVal && ValuesMap.insert(std::make_pair(&
I, *ReplVal)).second)
2504 HasChanged = ChangeStatus::CHANGED;
2510 SetterRFI.foreachUse(TrackValues,
F);
2512 bool UsedAssumedInformation =
false;
2513 A.checkForAllInstructions(CallCheck, *
this, {Instruction::Call},
2514 UsedAssumedInformation,
2520 if (HasChanged == ChangeStatus::CHANGED)
2521 ValuesMap.try_emplace(Entry);
2529 std::optional<Value *> getValueForCall(Attributor &
A,
const Instruction &
I,
2533 if (!CB || CB->
hasFnAttr(
"no_openmp") ||
2536 return std::nullopt;
2538 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
2539 auto &GetterRFI = OMPInfoCache.RFIs[OMPInfoCache.ICVs[ICV].Getter];
2540 auto &SetterRFI = OMPInfoCache.RFIs[OMPInfoCache.ICVs[ICV].Setter];
2544 if (CalledFunction ==
nullptr)
2546 if (CalledFunction == GetterRFI.Declaration)
2547 return std::nullopt;
2548 if (CalledFunction == SetterRFI.Declaration) {
2549 if (ICVReplacementValuesMap[ICV].
count(&
I))
2550 return ICVReplacementValuesMap[ICV].lookup(&
I);
2559 const auto *ICVTrackingAA =
A.getAAFor<AAICVTracker>(
2562 if (ICVTrackingAA->isAssumedTracked()) {
2563 std::optional<Value *> URV =
2564 ICVTrackingAA->getUniqueReplacementValue(ICV);
2575 std::optional<Value *>
2577 return std::nullopt;
2582 const Instruction *
I,
2583 Attributor &
A)
const override {
2584 const auto &ValuesMap = ICVReplacementValuesMap[ICV];
2585 if (ValuesMap.count(
I))
2586 return ValuesMap.lookup(
I);
2589 SmallPtrSet<const Instruction *, 16> Visited;
2592 std::optional<Value *> ReplVal;
2594 while (!Worklist.
empty()) {
2596 if (!Visited.
insert(CurrInst).second)
2604 if (ValuesMap.count(CurrInst)) {
2605 std::optional<Value *> NewReplVal = ValuesMap.lookup(CurrInst);
2608 ReplVal = NewReplVal;
2614 if (ReplVal != NewReplVal)
2620 std::optional<Value *> NewReplVal = getValueForCall(
A, *CurrInst, ICV);
2626 ReplVal = NewReplVal;
2632 if (ReplVal != NewReplVal)
2637 if (CurrBB ==
I->getParent() && ReplVal)
2642 Worklist.
push_back(Pred->getTerminator());
2649struct AAICVTrackerFunctionReturned : AAICVTracker {
2650 AAICVTrackerFunctionReturned(
const IRPosition &IRP, Attributor &
A)
2651 : AAICVTracker(IRP,
A) {}
2654 const std::string getAsStr(Attributor *)
const override {
2655 return "ICVTrackerFunctionReturned";
2659 void trackStatistics()
const override {}
2663 return ChangeStatus::UNCHANGED;
2668 InternalControlVar::ICV___last>
2669 ICVReplacementValuesMap;
2672 std::optional<Value *>
2674 return ICVReplacementValuesMap[ICV];
2679 const auto *ICVTrackingAA =
A.getAAFor<AAICVTracker>(
2682 if (!ICVTrackingAA->isAssumedTracked())
2683 return indicatePessimisticFixpoint();
2686 std::optional<Value *> &ReplVal = ICVReplacementValuesMap[ICV];
2687 std::optional<Value *> UniqueICVValue;
2690 std::optional<Value *> NewReplVal =
2691 ICVTrackingAA->getReplacementValue(ICV, &
I,
A);
2694 if (UniqueICVValue && UniqueICVValue != NewReplVal)
2697 UniqueICVValue = NewReplVal;
2702 bool UsedAssumedInformation =
false;
2703 if (!
A.checkForAllInstructions(CheckReturnInst, *
this, {Instruction::Ret},
2704 UsedAssumedInformation,
2706 UniqueICVValue =
nullptr;
2708 if (UniqueICVValue == ReplVal)
2711 ReplVal = UniqueICVValue;
2712 Changed = ChangeStatus::CHANGED;
2719struct AAICVTrackerCallSite : AAICVTracker {
2720 AAICVTrackerCallSite(
const IRPosition &IRP, Attributor &
A)
2721 : AAICVTracker(IRP,
A) {}
2724 assert(getAnchorScope() &&
"Expected anchor function");
2728 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
2730 auto ICVInfo = OMPInfoCache.ICVs[ICV];
2731 auto &Getter = OMPInfoCache.RFIs[ICVInfo.Getter];
2732 if (Getter.Declaration == getAssociatedFunction()) {
2733 AssociatedICV = ICVInfo.Kind;
2739 indicatePessimisticFixpoint();
2743 if (!ReplVal || !*ReplVal)
2744 return ChangeStatus::UNCHANGED;
2747 A.deleteAfterManifest(*getCtxI());
2749 return ChangeStatus::CHANGED;
2753 const std::string getAsStr(Attributor *)
const override {
2754 return "ICVTrackerCallSite";
2758 void trackStatistics()
const override {}
2761 std::optional<Value *> ReplVal;
2764 const auto *ICVTrackingAA =
A.getAAFor<AAICVTracker>(
2768 if (!ICVTrackingAA->isAssumedTracked())
2769 return indicatePessimisticFixpoint();
2771 std::optional<Value *> NewReplVal =
2772 ICVTrackingAA->getReplacementValue(AssociatedICV, getCtxI(),
A);
2774 if (ReplVal == NewReplVal)
2775 return ChangeStatus::UNCHANGED;
2777 ReplVal = NewReplVal;
2778 return ChangeStatus::CHANGED;
2783 std::optional<Value *>
2789struct AAICVTrackerCallSiteReturned : AAICVTracker {
2790 AAICVTrackerCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
2791 : AAICVTracker(IRP,
A) {}
2794 const std::string getAsStr(Attributor *)
const override {
2795 return "ICVTrackerCallSiteReturned";
2799 void trackStatistics()
const override {}
2803 return ChangeStatus::UNCHANGED;
2808 InternalControlVar::ICV___last>
2809 ICVReplacementValuesMap;
2813 std::optional<Value *>
2815 return ICVReplacementValuesMap[ICV];
2820 const auto *ICVTrackingAA =
A.getAAFor<AAICVTracker>(
2822 DepClassTy::REQUIRED);
2825 if (!ICVTrackingAA->isAssumedTracked())
2826 return indicatePessimisticFixpoint();
2829 std::optional<Value *> &ReplVal = ICVReplacementValuesMap[ICV];
2830 std::optional<Value *> NewReplVal =
2831 ICVTrackingAA->getUniqueReplacementValue(ICV);
2833 if (ReplVal == NewReplVal)
2836 ReplVal = NewReplVal;
2837 Changed = ChangeStatus::CHANGED;
2845static bool hasFunctionEndAsUniqueSuccessor(
const BasicBlock *BB) {
2851 return hasFunctionEndAsUniqueSuccessor(
Successor);
2854struct AAExecutionDomainFunction :
public AAExecutionDomain {
2855 AAExecutionDomainFunction(
const IRPosition &IRP, Attributor &
A)
2856 : AAExecutionDomain(IRP,
A) {}
2858 ~AAExecutionDomainFunction()
override {
delete RPOT; }
2862 assert(
F &&
"Expected anchor function");
2863 RPOT =
new ReversePostOrderTraversal<Function *>(
F);
2866 const std::string getAsStr(Attributor *)
const override {
2867 unsigned TotalBlocks = 0, InitialThreadBlocks = 0, AlignedBlocks = 0;
2868 for (
auto &It : BEDMap) {
2872 InitialThreadBlocks += It.getSecond().IsExecutedByInitialThreadOnly;
2873 AlignedBlocks += It.getSecond().IsReachedFromAlignedBarrierOnly &&
2874 It.getSecond().IsReachingAlignedBarrierOnly;
2876 return "[AAExecutionDomain] " + std::to_string(InitialThreadBlocks) +
"/" +
2877 std::to_string(AlignedBlocks) +
" of " +
2878 std::to_string(TotalBlocks) +
2879 " executed by initial thread / aligned";
2883 void trackStatistics()
const override {}
2887 for (
const BasicBlock &BB : *getAnchorScope()) {
2888 if (!isExecutedByInitialThreadOnly(BB))
2890 dbgs() <<
TAG <<
" Basic block @" << getAnchorScope()->getName() <<
" "
2891 << BB.
getName() <<
" is executed by a single thread.\n";
2900 SmallPtrSet<CallBase *, 16> DeletedBarriers;
2901 auto HandleAlignedBarrier = [&](CallBase *CB) {
2902 const ExecutionDomainTy &ED = CB ? CEDMap[{CB, PRE}] : BEDMap[
nullptr];
2903 if (!ED.IsReachedFromAlignedBarrierOnly ||
2904 ED.EncounteredNonLocalSideEffect)
2906 if (!ED.EncounteredAssumes.empty() && !
A.isModulePass())
2917 DeletedBarriers.
insert(CB);
2918 A.deleteAfterManifest(*CB);
2919 ++NumBarriersEliminated;
2920 Changed = ChangeStatus::CHANGED;
2921 }
else if (!ED.AlignedBarriers.empty()) {
2922 Changed = ChangeStatus::CHANGED;
2924 ED.AlignedBarriers.end());
2925 SmallSetVector<CallBase *, 16> Visited;
2926 while (!Worklist.
empty()) {
2928 if (!Visited.
insert(LastCB))
2932 if (!hasFunctionEndAsUniqueSuccessor(LastCB->
getParent()))
2934 if (!DeletedBarriers.
count(LastCB)) {
2935 ++NumBarriersEliminated;
2936 A.deleteAfterManifest(*LastCB);
2942 const ExecutionDomainTy &LastED = CEDMap[{LastCB, PRE}];
2943 Worklist.
append(LastED.AlignedBarriers.begin(),
2944 LastED.AlignedBarriers.end());
2950 if (!ED.EncounteredAssumes.empty() && (CB || !ED.AlignedBarriers.empty()))
2951 for (
auto *AssumeCB : ED.EncounteredAssumes)
2952 A.deleteAfterManifest(*AssumeCB);
2955 for (
auto *CB : AlignedBarriers)
2956 HandleAlignedBarrier(CB);
2960 HandleAlignedBarrier(
nullptr);
2965 bool isNoOpFence(
const FenceInst &FI)
const override {
2966 return getState().isValidState() && !NonNoOpFences.count(&FI);
2972 mergeInPredecessorBarriersAndAssumptions(Attributor &
A, ExecutionDomainTy &ED,
2973 const ExecutionDomainTy &PredED);
2978 bool mergeInPredecessor(Attributor &
A, ExecutionDomainTy &ED,
2979 const ExecutionDomainTy &PredED,
2980 bool InitialEdgeOnly =
false);
2983 bool handleCallees(Attributor &
A, ExecutionDomainTy &EntryBBED);
2990 bool isExecutedByInitialThreadOnly(
const BasicBlock &BB)
const override {
2991 if (!isValidState())
2993 assert(BB.
getParent() == getAnchorScope() &&
"Block is out of scope!");
2994 return BEDMap.lookup(&BB).IsExecutedByInitialThreadOnly;
2997 bool isExecutedInAlignedRegion(Attributor &
A,
2998 const Instruction &
I)
const override {
2999 assert(
I.getFunction() == getAnchorScope() &&
3000 "Instruction is out of scope!");
3001 if (!isValidState())
3004 bool ForwardIsOk =
true;
3013 if (CB != &
I && AlignedBarriers.contains(
const_cast<CallBase *
>(CB)))
3015 const auto &It = CEDMap.find({CB, PRE});
3016 if (It == CEDMap.end())
3018 if (!It->getSecond().IsReachingAlignedBarrierOnly)
3019 ForwardIsOk =
false;
3023 if (!CurI && !BEDMap.lookup(
I.getParent()).IsReachingAlignedBarrierOnly)
3024 ForwardIsOk =
false;
3032 if (CB != &
I && AlignedBarriers.contains(
const_cast<CallBase *
>(CB)))
3034 const auto &It = CEDMap.find({CB, POST});
3035 if (It == CEDMap.end())
3037 if (It->getSecond().IsReachedFromAlignedBarrierOnly)
3050 return BEDMap.lookup(
nullptr).IsReachedFromAlignedBarrierOnly;
3052 return BEDMap.lookup(PredBB).IsReachedFromAlignedBarrierOnly;
3062 ExecutionDomainTy getExecutionDomain(
const BasicBlock &BB)
const override {
3064 "No request should be made against an invalid state!");
3065 return BEDMap.lookup(&BB);
3067 std::pair<ExecutionDomainTy, ExecutionDomainTy>
3068 getExecutionDomain(
const CallBase &CB)
const override {
3070 "No request should be made against an invalid state!");
3071 return {CEDMap.lookup({&CB, PRE}), CEDMap.lookup({&CB, POST})};
3073 ExecutionDomainTy getFunctionExecutionDomain()
const override {
3075 "No request should be made against an invalid state!");
3076 return InterProceduralED;
3082 static bool isInitialThreadOnlyEdge(Attributor &
A, CondBrInst *
Edge,
3083 BasicBlock &SuccessorBB) {
3086 if (
Edge->getSuccessor(0) != &SuccessorBB)
3090 if (!Cmp || !
Cmp->isTrueWhenEqual() || !
Cmp->isEquality())
3098 if (
C->isAllOnesValue()) {
3100 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
3101 auto &RFI = OMPInfoCache.RFIs[OMPRTL___kmpc_target_init];
3102 CB = CB ? OpenMPOpt::getCallIfRegularCall(*CB, &RFI) : nullptr;
3105 ConstantStruct *KernelEnvC =
3107 ConstantInt *ExecModeC =
3108 KernelInfo::getExecModeFromKernelEnvironment(KernelEnvC);
3115 if (
II->getIntrinsicID() == Intrinsic::nvvm_read_ptx_sreg_tid_x)
3120 if (
II->getIntrinsicID() == Intrinsic::amdgcn_workitem_id_x)
3128 ExecutionDomainTy InterProceduralED;
3132 DenseMap<const BasicBlock *, ExecutionDomainTy> BEDMap;
3133 DenseMap<PointerIntPair<const CallBase *, 1, Direction>, ExecutionDomainTy>
3135 SmallSetVector<CallBase *, 16> AlignedBarriers;
3137 ReversePostOrderTraversal<Function *> *RPOT =
nullptr;
3140 static bool setAndRecord(
bool &R,
bool V) {
3148 SmallPtrSet<const FenceInst *, 8> NonNoOpFences;
3151void AAExecutionDomainFunction::mergeInPredecessorBarriersAndAssumptions(
3152 Attributor &
A, ExecutionDomainTy &ED,
const ExecutionDomainTy &PredED) {
3153 for (
auto *EA : PredED.EncounteredAssumes)
3154 ED.addAssumeInst(
A, *EA);
3156 for (
auto *AB : PredED.AlignedBarriers)
3157 ED.addAlignedBarrier(
A, *AB);
3160bool AAExecutionDomainFunction::mergeInPredecessor(
3161 Attributor &
A, ExecutionDomainTy &ED,
const ExecutionDomainTy &PredED,
3162 bool InitialEdgeOnly) {
3166 setAndRecord(ED.IsExecutedByInitialThreadOnly,
3167 InitialEdgeOnly || (PredED.IsExecutedByInitialThreadOnly &&
3168 ED.IsExecutedByInitialThreadOnly));
3170 Changed |= setAndRecord(ED.IsReachedFromAlignedBarrierOnly,
3171 ED.IsReachedFromAlignedBarrierOnly &&
3172 PredED.IsReachedFromAlignedBarrierOnly);
3173 Changed |= setAndRecord(ED.EncounteredNonLocalSideEffect,
3174 ED.EncounteredNonLocalSideEffect |
3175 PredED.EncounteredNonLocalSideEffect);
3177 if (ED.IsReachedFromAlignedBarrierOnly)
3178 mergeInPredecessorBarriersAndAssumptions(
A, ED, PredED);
3180 ED.clearAssumeInstAndAlignedBarriers();
3184bool AAExecutionDomainFunction::handleCallees(Attributor &
A,
3185 ExecutionDomainTy &EntryBBED) {
3187 auto PredForCallSite = [&](AbstractCallSite ACS) {
3188 const auto *EDAA =
A.getAAFor<AAExecutionDomain>(
3190 DepClassTy::OPTIONAL);
3191 if (!EDAA || !EDAA->getState().isValidState())
3194 EDAA->getExecutionDomain(*
cast<CallBase>(ACS.getInstruction())));
3198 ExecutionDomainTy ExitED;
3199 bool AllCallSitesKnown;
3200 if (
A.checkForAllCallSites(PredForCallSite, *
this,
3202 AllCallSitesKnown)) {
3203 for (
const auto &[CSInED, CSOutED] : CallSiteEDs) {
3204 mergeInPredecessor(
A, EntryBBED, CSInED);
3205 ExitED.IsReachingAlignedBarrierOnly &=
3206 CSOutED.IsReachingAlignedBarrierOnly;
3213 EntryBBED.IsExecutedByInitialThreadOnly =
false;
3214 EntryBBED.IsReachedFromAlignedBarrierOnly =
true;
3215 EntryBBED.EncounteredNonLocalSideEffect =
false;
3216 ExitED.IsReachingAlignedBarrierOnly =
false;
3218 EntryBBED.IsExecutedByInitialThreadOnly =
false;
3219 EntryBBED.IsReachedFromAlignedBarrierOnly =
false;
3220 EntryBBED.EncounteredNonLocalSideEffect =
true;
3221 ExitED.IsReachingAlignedBarrierOnly =
false;
3226 auto &FnED = BEDMap[
nullptr];
3227 Changed |= setAndRecord(FnED.IsReachedFromAlignedBarrierOnly,
3228 FnED.IsReachedFromAlignedBarrierOnly &
3229 EntryBBED.IsReachedFromAlignedBarrierOnly);
3230 Changed |= setAndRecord(FnED.IsReachingAlignedBarrierOnly,
3231 FnED.IsReachingAlignedBarrierOnly &
3232 ExitED.IsReachingAlignedBarrierOnly);
3233 Changed |= setAndRecord(FnED.IsExecutedByInitialThreadOnly,
3234 EntryBBED.IsExecutedByInitialThreadOnly);
3238ChangeStatus AAExecutionDomainFunction::updateImpl(Attributor &
A) {
3245 auto HandleAlignedBarrier = [&](CallBase &CB, ExecutionDomainTy &ED) {
3246 Changed |= AlignedBarriers.insert(&CB);
3248 auto &CallInED = CEDMap[{&CB, PRE}];
3249 Changed |= mergeInPredecessor(
A, CallInED, ED);
3250 CallInED.IsReachingAlignedBarrierOnly =
true;
3252 ED.EncounteredNonLocalSideEffect =
false;
3253 ED.IsReachedFromAlignedBarrierOnly =
true;
3255 ED.clearAssumeInstAndAlignedBarriers();
3256 ED.addAlignedBarrier(
A, CB);
3257 auto &CallOutED = CEDMap[{&CB, POST}];
3258 Changed |= mergeInPredecessor(
A, CallOutED, ED);
3262 A.getAAFor<AAIsDead>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
3268 SmallVector<Instruction *> SyncInstWorklist;
3269 for (
auto &RIt : *RPOT) {
3272 bool IsEntryBB = &BB == &EntryBB;
3275 bool AlignedBarrierLastInBlock = IsEntryBB && IsKernel;
3276 bool IsExplicitlyAligned = IsEntryBB && IsKernel;
3277 ExecutionDomainTy ED;
3284 if (LivenessAA && LivenessAA->isAssumedDead(&BB))
3288 if (LivenessAA && LivenessAA->isEdgeDead(PredBB, &BB))
3290 bool InitialEdgeOnly = isInitialThreadOnlyEdge(
3292 mergeInPredecessor(
A, ED, BEDMap[PredBB], InitialEdgeOnly);
3298 for (Instruction &
I : BB) {
3299 bool UsedAssumedInformation;
3300 if (
A.isAssumedDead(
I, *
this, LivenessAA, UsedAssumedInformation,
3301 false, DepClassTy::OPTIONAL,
3309 ED.addAssumeInst(
A, *AI);
3313 if (
II->isAssumeLikeIntrinsic())
3318 if (!ED.EncounteredNonLocalSideEffect) {
3320 if (ED.IsReachedFromAlignedBarrierOnly)
3325 case AtomicOrdering::NotAtomic:
3327 case AtomicOrdering::Unordered:
3329 case AtomicOrdering::Monotonic:
3331 case AtomicOrdering::Acquire:
3333 case AtomicOrdering::Release:
3335 case AtomicOrdering::AcquireRelease:
3337 case AtomicOrdering::SequentiallyConsistent:
3341 NonNoOpFences.insert(FI);
3346 bool IsAlignedBarrier =
3350 AlignedBarrierLastInBlock &= IsNoSync;
3351 IsExplicitlyAligned &= IsNoSync;
3357 if (IsAlignedBarrier) {
3358 HandleAlignedBarrier(*CB, ED);
3359 AlignedBarrierLastInBlock =
true;
3360 IsExplicitlyAligned =
true;
3366 if (!ED.EncounteredNonLocalSideEffect &&
3368 ED.EncounteredNonLocalSideEffect =
true;
3370 ED.IsReachedFromAlignedBarrierOnly =
false;
3378 auto &CallInED = CEDMap[{CB, PRE}];
3379 Changed |= mergeInPredecessor(
A, CallInED, ED);
3385 if (!IsNoSync && Callee && !
Callee->isDeclaration()) {
3386 const auto *EDAA =
A.getAAFor<AAExecutionDomain>(
3388 if (EDAA && EDAA->getState().isValidState()) {
3389 const auto &CalleeED = EDAA->getFunctionExecutionDomain();
3390 ED.IsReachedFromAlignedBarrierOnly =
3391 CalleeED.IsReachedFromAlignedBarrierOnly;
3392 AlignedBarrierLastInBlock = ED.IsReachedFromAlignedBarrierOnly;
3393 if (IsNoSync || !CalleeED.IsReachedFromAlignedBarrierOnly)
3394 ED.EncounteredNonLocalSideEffect |=
3395 CalleeED.EncounteredNonLocalSideEffect;
3397 ED.EncounteredNonLocalSideEffect =
3398 CalleeED.EncounteredNonLocalSideEffect;
3399 if (!CalleeED.IsReachingAlignedBarrierOnly) {
3401 setAndRecord(CallInED.IsReachingAlignedBarrierOnly,
false);
3404 if (CalleeED.IsReachedFromAlignedBarrierOnly)
3405 mergeInPredecessorBarriersAndAssumptions(
A, ED, CalleeED);
3406 auto &CallOutED = CEDMap[{CB, POST}];
3407 Changed |= mergeInPredecessor(
A, CallOutED, ED);
3412 ED.IsReachedFromAlignedBarrierOnly =
false;
3413 Changed |= setAndRecord(CallInED.IsReachingAlignedBarrierOnly,
false);
3416 AlignedBarrierLastInBlock &= ED.IsReachedFromAlignedBarrierOnly;
3418 auto &CallOutED = CEDMap[{CB, POST}];
3419 Changed |= mergeInPredecessor(
A, CallOutED, ED);
3422 if (!
I.mayHaveSideEffects() && !
I.mayReadFromMemory())
3428 const auto *MemAA =
A.getAAFor<AAMemoryLocation>(
3436 if (MemAA && MemAA->getState().isValidState() &&
3437 MemAA->checkForAllAccessesToMemoryKind(
3442 auto &InfoCache =
A.getInfoCache();
3443 if (!
I.mayHaveSideEffects() && InfoCache.isOnlyUsedByAssume(
I))
3447 if (LI->hasMetadata(LLVMContext::MD_invariant_load))
3450 if (!ED.EncounteredNonLocalSideEffect &&
3452 ED.EncounteredNonLocalSideEffect =
true;
3455 bool IsEndAndNotReachingAlignedBarriersOnly =
false;
3457 !BB.getTerminator()->getNumSuccessors()) {
3459 Changed |= mergeInPredecessor(
A, InterProceduralED, ED);
3461 auto &FnED = BEDMap[
nullptr];
3462 if (IsKernel && !IsExplicitlyAligned)
3463 FnED.IsReachingAlignedBarrierOnly =
false;
3464 Changed |= mergeInPredecessor(
A, FnED, ED);
3466 if (!FnED.IsReachingAlignedBarrierOnly) {
3467 IsEndAndNotReachingAlignedBarriersOnly =
true;
3468 SyncInstWorklist.
push_back(BB.getTerminator());
3469 auto &BBED = BEDMap[&BB];
3470 Changed |= setAndRecord(BBED.IsReachingAlignedBarrierOnly,
false);
3474 ExecutionDomainTy &StoredED = BEDMap[&BB];
3475 ED.IsReachingAlignedBarrierOnly = StoredED.IsReachingAlignedBarrierOnly &&
3476 !IsEndAndNotReachingAlignedBarriersOnly;
3482 if (ED.IsExecutedByInitialThreadOnly !=
3483 StoredED.IsExecutedByInitialThreadOnly ||
3484 ED.IsReachedFromAlignedBarrierOnly !=
3485 StoredED.IsReachedFromAlignedBarrierOnly ||
3486 ED.EncounteredNonLocalSideEffect !=
3487 StoredED.EncounteredNonLocalSideEffect)
3491 StoredED = std::move(ED);
3496 SmallSetVector<BasicBlock *, 16> Visited;
3497 while (!SyncInstWorklist.
empty()) {
3500 bool HitAlignedBarrierOrKnownEnd =
false;
3505 auto &CallOutED = CEDMap[{CB, POST}];
3506 Changed |= setAndRecord(CallOutED.IsReachingAlignedBarrierOnly,
false);
3507 auto &CallInED = CEDMap[{CB, PRE}];
3508 HitAlignedBarrierOrKnownEnd =
3509 AlignedBarriers.count(CB) || !CallInED.IsReachingAlignedBarrierOnly;
3510 if (HitAlignedBarrierOrKnownEnd)
3512 Changed |= setAndRecord(CallInED.IsReachingAlignedBarrierOnly,
false);
3514 if (HitAlignedBarrierOrKnownEnd)
3518 if (LivenessAA && LivenessAA->isEdgeDead(PredBB, SyncBB))
3520 if (!Visited.
insert(PredBB))
3522 auto &PredED = BEDMap[PredBB];
3523 if (setAndRecord(PredED.IsReachingAlignedBarrierOnly,
false)) {
3525 SyncInstWorklist.
push_back(PredBB->getTerminator());
3528 if (SyncBB != &EntryBB)
3531 setAndRecord(InterProceduralED.IsReachingAlignedBarrierOnly,
false);
3534 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
3539struct AAHeapToShared :
public StateWrapper<BooleanState, AbstractAttribute> {
3540 using Base = StateWrapper<BooleanState, AbstractAttribute>;
3541 AAHeapToShared(
const IRPosition &IRP, Attributor &
A) :
Base(IRP) {}
3544 static AAHeapToShared &createForPosition(
const IRPosition &IRP,
3548 virtual bool isAssumedHeapToShared(CallBase &CB)
const = 0;
3552 virtual bool isAssumedHeapToSharedRemovedFree(CallBase &CB)
const = 0;
3555 StringRef
getName()
const override {
return "AAHeapToShared"; }
3558 const char *getIdAddr()
const override {
return &ID; }
3562 static bool classof(
const AbstractAttribute *AA) {
3567 static const char ID;
3570struct AAHeapToSharedFunction :
public AAHeapToShared {
3571 AAHeapToSharedFunction(
const IRPosition &IRP, Attributor &
A)
3572 : AAHeapToShared(IRP,
A) {}
3574 const std::string getAsStr(Attributor *)
const override {
3575 return "[AAHeapToShared] " + std::to_string(MallocCalls.size()) +
3576 " malloc calls eligible.";
3580 void trackStatistics()
const override {}
3584 void findPotentialRemovedFreeCalls(Attributor &
A) {
3585 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
3586 auto &FreeRFI = OMPInfoCache.RFIs[OMPRTL___kmpc_free_shared];
3588 PotentialRemovedFreeCalls.clear();
3590 for (CallBase *CB : MallocCalls) {
3592 for (
auto *U : CB->
users()) {
3594 if (
C &&
C->getCalledFunction() == FreeRFI.Declaration)
3598 if (FreeCalls.
size() != 1)
3601 PotentialRemovedFreeCalls.insert(FreeCalls.
front());
3607 indicatePessimisticFixpoint();
3611 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
3612 auto &RFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
3613 if (!RFI.Declaration)
3617 [](
const IRPosition &,
const AbstractAttribute *,
3618 bool &) -> std::optional<Value *> {
return nullptr; };
3621 const OMPInformationCache::RuntimeFunctionInfo::UseVector *
Uses =
3622 RFI.getUseVector(*
F);
3626 for (Use *U : *
Uses)
3628 MallocCalls.insert(CB);
3633 findPotentialRemovedFreeCalls(
A);
3636 bool isAssumedHeapToShared(CallBase &CB)
const override {
3637 return isValidState() && MallocCalls.count(&CB);
3640 bool isAssumedHeapToSharedRemovedFree(CallBase &CB)
const override {
3641 return isValidState() && PotentialRemovedFreeCalls.count(&CB);
3645 if (MallocCalls.empty())
3646 return ChangeStatus::UNCHANGED;
3648 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
3649 auto &FreeCall = OMPInfoCache.RFIs[OMPRTL___kmpc_free_shared];
3653 DepClassTy::OPTIONAL);
3656 for (CallBase *CB : MallocCalls) {
3658 if (HS &&
HS->isAssumedHeapToStack(*CB))
3663 for (
auto *U : CB->
users()) {
3665 if (
C &&
C->getCalledFunction() == FreeCall.Declaration)
3668 if (FreeCalls.
size() != 1)
3675 <<
" with shared memory."
3676 <<
" Shared memory usage is limited to "
3682 <<
" with " << AllocSize->getZExtValue()
3683 <<
" bytes of shared memory\n");
3688 Type *Int8Ty = Type::getInt8Ty(
M->getContext());
3689 Type *Int8ArrTy = ArrayType::get(Int8Ty, AllocSize->getZExtValue());
3690 auto *SharedMem =
new GlobalVariable(
3694 static_cast<unsigned>(AddressSpace::Shared));
3696 SharedMem, PointerType::getUnqual(
M->getContext()));
3698 auto Remark = [&](OptimizationRemark
OR) {
3699 return OR <<
"Replaced globalized variable with "
3700 <<
ore::NV(
"SharedMemory", AllocSize->getZExtValue())
3701 << (AllocSize->isOne() ?
" byte " :
" bytes ")
3702 <<
"of shared memory.";
3704 A.emitRemark<OptimizationRemark>(CB,
"OMP111",
Remark);
3706 MaybeAlign
Alignment = CB->getRetAlign();
3708 "HeapToShared on allocation without alignment attribute");
3712 A.deleteAfterManifest(*CB);
3713 A.deleteAfterManifest(*FreeCalls.
front());
3715 SharedMemoryUsed += AllocSize->getZExtValue();
3716 NumBytesMovedToSharedMemory = SharedMemoryUsed;
3717 Changed = ChangeStatus::CHANGED;
3724 if (MallocCalls.empty())
3725 return indicatePessimisticFixpoint();
3726 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
3727 auto &RFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
3728 if (!RFI.Declaration)
3729 return ChangeStatus::UNCHANGED;
3733 auto NumMallocCalls = MallocCalls.size();
3736 for (User *U : RFI.Declaration->
users()) {
3738 if (CB->getCaller() !=
F)
3740 if (!MallocCalls.count(CB))
3743 MallocCalls.remove(CB);
3746 const auto *ED =
A.getAAFor<AAExecutionDomain>(
3748 if (!ED || !ED->isExecutedByInitialThreadOnly(*CB))
3749 MallocCalls.remove(CB);
3753 findPotentialRemovedFreeCalls(
A);
3755 if (NumMallocCalls != MallocCalls.size())
3756 return ChangeStatus::CHANGED;
3758 return ChangeStatus::UNCHANGED;
3762 SmallSetVector<CallBase *, 4> MallocCalls;
3764 SmallPtrSet<CallBase *, 4> PotentialRemovedFreeCalls;
3766 unsigned SharedMemoryUsed = 0;
3769struct AAKernelInfo :
public StateWrapper<KernelInfoState, AbstractAttribute> {
3770 using Base = StateWrapper<KernelInfoState, AbstractAttribute>;
3771 AAKernelInfo(
const IRPosition &IRP, Attributor &
A) :
Base(IRP) {}
3775 static bool requiresCalleeForCallBase() {
return false; }
3778 void trackStatistics()
const override {}
3781 const std::string getAsStr(Attributor *)
const override {
3782 if (!isValidState())
3784 return std::string(SPMDCompatibilityTracker.isAssumed() ?
"SPMD"
3786 std::string(SPMDCompatibilityTracker.isAtFixpoint() ?
" [FIX]"
3788 std::string(
" #PRs: ") +
3789 (ReachedKnownParallelRegions.isValidState()
3790 ? std::to_string(ReachedKnownParallelRegions.size())
3792 ", #Unknown PRs: " +
3793 (ReachedUnknownParallelRegions.isValidState()
3794 ? std::to_string(ReachedUnknownParallelRegions.size())
3796 ", #Reaching Kernels: " +
3797 (ReachingKernelEntries.isValidState()
3798 ? std::to_string(ReachingKernelEntries.size())
3801 (ParallelLevels.isValidState()
3802 ? std::to_string(ParallelLevels.size())
3804 ", NestedPar: " + (NestedParallelism ?
"yes" :
"no");
3808 static AAKernelInfo &createForPosition(
const IRPosition &IRP, Attributor &
A);
3811 StringRef
getName()
const override {
return "AAKernelInfo"; }
3814 const char *getIdAddr()
const override {
return &ID; }
3817 static bool classof(
const AbstractAttribute *AA) {
3821 static const char ID;
3825static bool isStrictFence(
const Instruction &
I) {
3841 switch (Parsed->first) {
3842 case AtomicScope::Single:
3843 case AtomicScope::Wavefront:
3844 case AtomicScope::Workgroup:
3846 case AtomicScope::Cluster:
3847 case AtomicScope::Device:
3848 case AtomicScope::System:
3856struct AAKernelInfoFunction : AAKernelInfo {
3857 AAKernelInfoFunction(
const IRPosition &IRP, Attributor &
A)
3858 : AAKernelInfo(IRP,
A) {}
3860 SmallPtrSet<Instruction *, 4> GuardedInstructions;
3862 SmallPtrSetImpl<Instruction *> &getGuardedInstructions() {
3863 return GuardedInstructions;
3866 void setConfigurationOfKernelEnvironment(ConstantStruct *ConfigC) {
3868 KernelEnvC, ConfigC, {KernelInfo::ConfigurationIdx});
3869 assert(NewKernelEnvC &&
"Failed to create new kernel environment");
3873#define KERNEL_ENVIRONMENT_CONFIGURATION_SETTER(MEMBER) \
3874 void set##MEMBER##OfKernelEnvironment(ConstantInt *NewVal) { \
3875 ConstantStruct *ConfigC = \
3876 KernelInfo::getConfigurationFromKernelEnvironment(KernelEnvC); \
3877 Constant *NewConfigC = ConstantFoldInsertValueInstruction( \
3878 ConfigC, NewVal, {KernelInfo::MEMBER##Idx}); \
3879 assert(NewConfigC && "Failed to create new configuration environment"); \
3880 setConfigurationOfKernelEnvironment(cast<ConstantStruct>(NewConfigC)); \
3891#undef KERNEL_ENVIRONMENT_CONFIGURATION_SETTER
3898 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
3902 OMPInformationCache::RuntimeFunctionInfo &InitRFI =
3903 OMPInfoCache.RFIs[OMPRTL___kmpc_target_init];
3904 OMPInformationCache::RuntimeFunctionInfo &DeinitRFI =
3905 OMPInfoCache.RFIs[OMPRTL___kmpc_target_deinit];
3909 auto StoreCallBase = [](
Use &U,
3910 OMPInformationCache::RuntimeFunctionInfo &RFI,
3912 CallBase *CB = OpenMPOpt::getCallIfRegularCall(U, &RFI);
3914 "Unexpected use of __kmpc_target_init or __kmpc_target_deinit!");
3916 "Multiple uses of __kmpc_target_init or __kmpc_target_deinit!");
3922 StoreCallBase(U, InitRFI, KernelInitCB);
3926 DeinitRFI.foreachUse(
3928 StoreCallBase(U, DeinitRFI, KernelDeinitCB);
3934 if (!KernelInitCB || !KernelDeinitCB)
3938 ReachingKernelEntries.insert(Fn);
3939 IsKernelEntry =
true;
3947 KernelConfigurationSimplifyCB =
3949 bool &UsedAssumedInformation) -> std::optional<Constant *> {
3950 if (!isAtFixpoint()) {
3953 UsedAssumedInformation =
true;
3959 A.registerGlobalVariableSimplificationCallback(
3960 *KernelEnvGV, KernelConfigurationSimplifyCB);
3963 bool CanChangeToSPMD = OMPInfoCache.runtimeFnsAvailable(
3964 {OMPRTL___kmpc_get_hardware_thread_id_in_block,
3965 OMPRTL___kmpc_barrier_simple_spmd});
3969 KernelInfo::getExecModeFromKernelEnvironment(KernelEnvC);
3974 SPMDCompatibilityTracker.indicateOptimisticFixpoint();
3978 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
3980 setExecModeOfKernelEnvironment(AssumedExecModeC);
3984 auto [MinThreads, MaxThreads] =
3987 setMinThreadsOfKernelEnvironment(ConstantInt::get(Int32Ty, MinThreads));
3989 setMaxThreadsOfKernelEnvironment(ConstantInt::get(Int32Ty, MaxThreads));
3990 auto [MinTeams, MaxTeams] =
3993 setMinTeamsOfKernelEnvironment(ConstantInt::get(Int32Ty, MinTeams));
3995 setMaxTeamsOfKernelEnvironment(ConstantInt::get(Int32Ty, MaxTeams));
3998 KernelInfo::getMayUseNestedParallelismFromKernelEnvironment(KernelEnvC);
3999 ConstantInt *AssumedMayUseNestedParallelismC = ConstantInt::get(
4001 setMayUseNestedParallelismOfKernelEnvironment(
4002 AssumedMayUseNestedParallelismC);
4006 KernelInfo::getUseGenericStateMachineFromKernelEnvironment(
4009 ConstantInt::get(UseGenericStateMachineC->
getIntegerType(),
false);
4010 setUseGenericStateMachineOfKernelEnvironment(
4011 AssumedUseGenericStateMachineC);
4017 if (!OMPInfoCache.RFIs[RFKind].Declaration)
4019 A.registerVirtualUseCallback(*OMPInfoCache.RFIs[RFKind].Declaration, CB);
4023 auto AddDependence = [](
Attributor &
A,
const AAKernelInfo *KI,
4039 if (SPMDCompatibilityTracker.isValidState())
4040 return AddDependence(
A,
this, QueryingAA);
4042 if (!ReachedKnownParallelRegions.isValidState())
4043 return AddDependence(
A,
this, QueryingAA);
4049 RegisterVirtualUse(OMPRTL___kmpc_get_max_team_threads,
4050 CustomStateMachineUseCB);
4051 RegisterVirtualUse(OMPRTL___kmpc_barrier_simple_generic,
4052 CustomStateMachineUseCB);
4053 RegisterVirtualUse(OMPRTL___kmpc_kernel_parallel,
4054 CustomStateMachineUseCB);
4055 RegisterVirtualUse(OMPRTL___kmpc_kernel_end_parallel,
4056 CustomStateMachineUseCB);
4060 if (SPMDCompatibilityTracker.isAtFixpoint())
4067 if (!SPMDCompatibilityTracker.isValidState())
4068 return AddDependence(
A,
this, QueryingAA);
4071 RegisterVirtualUse(OMPRTL___kmpc_get_hardware_thread_id_in_block,
4080 if (!SPMDCompatibilityTracker.isValidState())
4081 return AddDependence(
A,
this, QueryingAA);
4082 if (SPMDCompatibilityTracker.empty())
4083 return AddDependence(
A,
this, QueryingAA);
4084 if (!mayContainParallelRegion())
4085 return AddDependence(
A,
this, QueryingAA);
4088 RegisterVirtualUse(OMPRTL___kmpc_barrier_simple_spmd, SPMDBarrierUseCB);
4092 static std::string sanitizeForGlobalName(std::string S) {
4096 return !((C >=
'a' && C <=
'z') || (C >=
'A' && C <=
'Z') ||
4097 (C >=
'0' && C <=
'9') || C ==
'_');
4108 if (!KernelInitCB || !KernelDeinitCB)
4109 return ChangeStatus::UNCHANGED;
4113 bool HasBuiltStateMachine =
true;
4114 if (!changeToSPMDMode(
A,
Changed)) {
4116 HasBuiltStateMachine = buildCustomStateMachine(
A,
Changed);
4118 HasBuiltStateMachine =
false;
4122 ConstantStruct *ExistingKernelEnvC =
4124 ConstantInt *OldUseGenericStateMachineVal =
4125 KernelInfo::getUseGenericStateMachineFromKernelEnvironment(
4126 ExistingKernelEnvC);
4127 if (!HasBuiltStateMachine)
4128 setUseGenericStateMachineOfKernelEnvironment(
4129 OldUseGenericStateMachineVal);
4132 GlobalVariable *KernelEnvGV =
4136 Changed = ChangeStatus::CHANGED;
4142 void insertInstructionGuardsHelper(Attributor &
A) {
4143 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
4145 auto CreateGuardedRegion = [&](
Instruction *RegionStartI,
4147 LoopInfo *LI =
nullptr;
4148 DominatorTree *DT =
nullptr;
4149 MemorySSAUpdater *MSU =
nullptr;
4178 DT, LI, MSU,
"region.guarded.end");
4181 MSU,
"region.barrier");
4184 DT, LI, MSU,
"region.exit");
4186 SplitBlock(ParentBB, RegionStartI, DT, LI, MSU,
"region.guarded");
4189 "Expected a different CFG");
4192 ParentBB, ParentBB->
getTerminator(), DT, LI, MSU,
"region.check.tid");
4195 A.registerManifestAddedBasicBlock(*RegionEndBB);
4196 A.registerManifestAddedBasicBlock(*RegionBarrierBB);
4197 A.registerManifestAddedBasicBlock(*RegionExitBB);
4198 A.registerManifestAddedBasicBlock(*RegionStartBB);
4199 A.registerManifestAddedBasicBlock(*RegionCheckTidBB);
4201 bool HasBroadcastValues =
false;
4204 for (Instruction &
I : *RegionStartBB) {
4206 for (Use &U :
I.uses()) {
4212 if (OutsideUses.
empty())
4215 HasBroadcastValues =
true;
4219 auto *SharedMem =
new GlobalVariable(
4220 M,
I.getType(),
false,
4222 sanitizeForGlobalName(
4223 (
I.getName() +
".guarded.output.alloc").str()),
4225 static_cast<unsigned>(AddressSpace::Shared));
4228 new StoreInst(&
I, SharedMem,
4231 LoadInst *LoadI =
new LoadInst(
4232 I.getType(), SharedMem,
I.getName() +
".guarded.output.load",
4236 for (Use *U : OutsideUses)
4237 A.changeUseAfterManifest(*U, *LoadI);
4240 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
4245 OpenMPIRBuilder::LocationDescription Loc(ParentBB->
end(),
DL);
4247 uint32_t SrcLocStrSize;
4256 OpenMPIRBuilder::LocationDescription LocRegionCheckTid(
4257 RegionCheckTidBB->
end(),
DL);
4259 FunctionCallee HardwareTidFn =
4261 M, OMPRTL___kmpc_get_hardware_thread_id_in_block);
4265 OMPInfoCache.setCallingConvention(HardwareTidFn, Tid);
4267 OMPInfoCache.OMPBuilder.
Builder
4268 .
CreateCondBr(TidCheck, RegionStartBB, RegionBarrierBB)
4273 FunctionCallee BarrierFn =
4275 M, OMPRTL___kmpc_barrier_simple_spmd);
4280 OMPInfoCache.setCallingConvention(BarrierFn, Barrier);
4283 if (HasBroadcastValues) {
4288 OMPInfoCache.setCallingConvention(BarrierFn, Barrier);
4292 auto &AllocSharedRFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
4293 SmallPtrSet<BasicBlock *, 8> Visited;
4294 for (Instruction *GuardedI : SPMDCompatibilityTracker) {
4296 if (!Visited.
insert(BB).second)
4302 while (++IP != IPEnd) {
4303 if (!IP->mayHaveSideEffects() && !IP->mayReadFromMemory())
4306 if (OpenMPOpt::getCallIfRegularCall(*
I, &AllocSharedRFI))
4309 if (isStrictFence(*
I) || !
I->user_empty() ||
4310 !SPMDCompatibilityTracker.contains(
I)) {
4311 LastEffect =
nullptr;
4318 for (
auto &Reorder : Reorders)
4319 Reorder.first->moveBefore(Reorder.second->getIterator());
4324 for (Instruction *GuardedI : SPMDCompatibilityTracker) {
4326 auto *CalleeAA =
A.lookupAAFor<AAKernelInfo>(
4329 assert(CalleeAA !=
nullptr &&
"Expected Callee AAKernelInfo");
4332 if (CalleeAAFunction.getGuardedInstructions().contains(GuardedI))
4335 Instruction *GuardedRegionStart =
nullptr, *GuardedRegionEnd =
nullptr;
4336 for (Instruction &
I : *BB) {
4338 if (isStrictFence(
I)) {
4339 if (SPMDCompatibilityTracker.contains(&
I))
4340 CalleeAAFunction.getGuardedInstructions().insert(&
I);
4341 if (GuardedRegionStart) {
4343 std::make_pair(GuardedRegionStart, GuardedRegionEnd));
4344 GuardedRegionStart =
nullptr;
4345 GuardedRegionEnd =
nullptr;
4352 if (SPMDCompatibilityTracker.contains(&
I)) {
4353 CalleeAAFunction.getGuardedInstructions().insert(&
I);
4354 if (GuardedRegionStart)
4355 GuardedRegionEnd = &
I;
4357 GuardedRegionStart = GuardedRegionEnd = &
I;
4364 if (GuardedRegionStart) {
4366 std::make_pair(GuardedRegionStart, GuardedRegionEnd));
4367 GuardedRegionStart =
nullptr;
4368 GuardedRegionEnd =
nullptr;
4373 for (
auto &GR : GuardedRegions)
4374 CreateGuardedRegion(GR.first, GR.second);
4377 void forceSingleThreadPerWorkgroupHelper(Attributor &
A) {
4386 auto &Ctx = getAnchorValue().getContext();
4393 KernelInitCB->
getNextNode(),
"main.thread.user_code");
4398 A.registerManifestAddedBasicBlock(*InitBB);
4399 A.registerManifestAddedBasicBlock(*UserCodeBB);
4400 A.registerManifestAddedBasicBlock(*ReturnBB);
4409 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
4410 FunctionCallee ThreadIdInBlockFn =
4412 M, OMPRTL___kmpc_get_hardware_thread_id_in_block);
4415 CallInst *ThreadIdInBlock =
4417 OMPInfoCache.setCallingConvention(ThreadIdInBlockFn, ThreadIdInBlock);
4423 ConstantInt::get(ThreadIdInBlock->
getType(), 0),
4424 "thread.is_main", InitBB);
4430 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
4432 if (!SPMDCompatibilityTracker.isAssumed()) {
4433 for (Instruction *NonCompatibleI : SPMDCompatibilityTracker) {
4434 if (!NonCompatibleI)
4439 if (OMPInfoCache.RTLFunctions.contains(CB->getCalledFunction()))
4442 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
4443 ORA <<
"Value has potential side effects preventing SPMD-mode "
4446 ORA <<
". Add `[[omp::assume(\"ompx_spmd_amenable\")]]` to "
4447 "the called function to override";
4451 A.emitRemark<OptimizationRemarkAnalysis>(NonCompatibleI,
"OMP121",
4455 << *NonCompatibleI <<
"\n");
4467 Kernel = CB->getCaller();
4472 ConstantStruct *ExistingKernelEnvC =
4475 KernelInfo::getExecModeFromKernelEnvironment(ExistingKernelEnvC);
4481 Changed = ChangeStatus::CHANGED;
4486 if (mayContainParallelRegion()) {
4487 insertInstructionGuardsHelper(
A);
4489 forceSingleThreadPerWorkgroupHelper(
A);
4490 setMaxThreadsOfKernelEnvironment(
4497 "Initially non-SPMD kernel has SPMD exec mode!");
4498 setExecModeOfKernelEnvironment(
4502 ++NumOpenMPTargetRegionKernelsSPMD;
4506 OMPInfoCache.SPMDizedKernels.insert(
Kernel);
4508 auto Remark = [&](OptimizationRemark
OR) {
4509 return OR <<
"Transformed generic-mode kernel to SPMD-mode.";
4511 A.emitRemark<OptimizationRemark>(KernelInitCB,
"OMP120",
Remark);
4521 if (!ReachedKnownParallelRegions.isValidState())
4524 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
4525 if (!OMPInfoCache.runtimeFnsAvailable({OMPRTL___kmpc_get_max_team_threads,
4526 OMPRTL___kmpc_barrier_simple_generic,
4527 OMPRTL___kmpc_kernel_parallel,
4528 OMPRTL___kmpc_kernel_end_parallel}))
4531 ConstantStruct *ExistingKernelEnvC =
4538 ConstantInt *UseStateMachineC =
4539 KernelInfo::getUseGenericStateMachineFromKernelEnvironment(
4540 ExistingKernelEnvC);
4541 ConstantInt *ModeC =
4542 KernelInfo::getExecModeFromKernelEnvironment(ExistingKernelEnvC);
4547 if (UseStateMachineC->
isZero() ||
4551 Changed = ChangeStatus::CHANGED;
4554 setUseGenericStateMachineOfKernelEnvironment(
4561 if (!mayContainParallelRegion()) {
4562 ++NumOpenMPTargetRegionKernelsWithoutStateMachine;
4564 auto Remark = [&](OptimizationRemark
OR) {
4565 return OR <<
"Removing unused state machine from generic-mode kernel.";
4567 A.emitRemark<OptimizationRemark>(KernelInitCB,
"OMP130",
Remark);
4573 if (ReachedUnknownParallelRegions.empty()) {
4574 ++NumOpenMPTargetRegionKernelsCustomStateMachineWithoutFallback;
4576 auto Remark = [&](OptimizationRemark
OR) {
4577 return OR <<
"Rewriting generic-mode kernel with a customized state "
4580 A.emitRemark<OptimizationRemark>(KernelInitCB,
"OMP131",
Remark);
4582 ++NumOpenMPTargetRegionKernelsCustomStateMachineWithFallback;
4584 auto Remark = [&](OptimizationRemarkAnalysis
OR) {
4585 return OR <<
"Generic-mode kernel is executed with a customized state "
4586 "machine that requires a fallback.";
4588 A.emitRemark<OptimizationRemarkAnalysis>(KernelInitCB,
"OMP132",
Remark);
4591 for (CallBase *UnknownParallelRegionCB : ReachedUnknownParallelRegions) {
4592 if (!UnknownParallelRegionCB)
4594 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
4595 return ORA <<
"Call may contain unknown parallel regions. Use "
4596 <<
"`[[omp::assume(\"omp_no_parallelism\")]]` to "
4599 A.emitRemark<OptimizationRemarkAnalysis>(UnknownParallelRegionCB,
4632 auto &Ctx = getAnchorValue().getContext();
4636 BasicBlock *InitBB = KernelInitCB->getParent();
4638 KernelInitCB->getNextNode(),
"thread.user_code.check");
4642 Ctx,
"worker_state_machine.begin",
Kernel, UserCodeEntryBB);
4644 Ctx,
"worker_state_machine.finished",
Kernel, UserCodeEntryBB);
4646 Ctx,
"worker_state_machine.is_active.check",
Kernel, UserCodeEntryBB);
4649 Kernel, UserCodeEntryBB);
4652 Kernel, UserCodeEntryBB);
4654 Ctx,
"worker_state_machine.done.barrier",
Kernel, UserCodeEntryBB);
4655 A.registerManifestAddedBasicBlock(*InitBB);
4656 A.registerManifestAddedBasicBlock(*UserCodeEntryBB);
4657 A.registerManifestAddedBasicBlock(*IsWorkerCheckBB);
4658 A.registerManifestAddedBasicBlock(*StateMachineBeginBB);
4659 A.registerManifestAddedBasicBlock(*StateMachineFinishedBB);
4660 A.registerManifestAddedBasicBlock(*StateMachineIsActiveCheckBB);
4661 A.registerManifestAddedBasicBlock(*StateMachineIfCascadeCurrentBB);
4662 A.registerManifestAddedBasicBlock(*StateMachineEndParallelBB);
4663 A.registerManifestAddedBasicBlock(*StateMachineDoneBarrierBB);
4665 const DebugLoc &DLoc = KernelInitCB->getDebugLoc();
4671 ConstantInt::getAllOnesValue(KernelInitCB->getType()),
4672 "thread.is_worker", InitBB);
4681 FunctionCallee MaxTeamThreadsFn =
4683 M, OMPRTL___kmpc_get_max_team_threads);
4684 Constant *IsSPMDArg = ConstantInt::get(OMPInfoCache.OMPBuilder.Int32, 0);
4686 MaxTeamThreadsFn, {IsSPMDArg},
"max_team_threads", IsWorkerCheckBB);
4687 OMPInfoCache.setCallingConvention(MaxTeamThreadsFn, MaxTeamThreads);
4691 "thread.is_main_or_worker", IsWorkerCheckBB);
4694 StateMachineFinishedBB, IsWorkerCheckBB);
4697 const DataLayout &
DL =
M.getDataLayout();
4698 Type *VoidPtrTy = PointerType::getUnqual(Ctx);
4700 new AllocaInst(VoidPtrTy,
DL.getAllocaAddrSpace(),
nullptr,
4705 OpenMPIRBuilder::LocationDescription(StateMachineBeginBB->
end(), DLoc));
4707 Value *Ident = KernelInfo::getIdentFromKernelEnvironment(KernelEnvC);
4708 Value *GTid = KernelInitCB;
4710 FunctionCallee BarrierFn =
4712 M, OMPRTL___kmpc_barrier_simple_generic);
4715 OMPInfoCache.setCallingConvention(BarrierFn, Barrier);
4719 (
unsigned int)AddressSpace::Generic) {
4720 WorkFnAI =
new AddrSpaceCastInst(
4721 WorkFnAI, PointerType::get(Ctx, (
unsigned int)AddressSpace::Generic),
4722 WorkFnAI->
getName() +
".generic", StateMachineBeginBB);
4726 FunctionCallee KernelParallelFn =
4728 M, OMPRTL___kmpc_kernel_parallel);
4730 KernelParallelFn, {WorkFnAI},
"worker.is_active", StateMachineBeginBB);
4731 OMPInfoCache.setCallingConvention(KernelParallelFn, IsActiveWorker);
4733 Instruction *WorkFn =
new LoadInst(VoidPtrTy, WorkFnAI,
"worker.work_fn",
4734 StateMachineBeginBB);
4737 FunctionType *ParallelRegionFnTy = FunctionType::get(
4738 Type::getVoidTy(Ctx), {Type::getInt16Ty(Ctx), Type::getInt32Ty(Ctx)},
4744 StateMachineBeginBB);
4745 IsDone->setDebugLoc(DLoc);
4747 StateMachineIsActiveCheckBB, StateMachineBeginBB)
4751 StateMachineDoneBarrierBB, StateMachineIsActiveCheckBB)
4757 const unsigned int WrapperFunctionArgNo = 6;
4762 for (
int I = 0,
E = ReachedKnownParallelRegions.size();
I <
E; ++
I) {
4763 auto *CB = ReachedKnownParallelRegions[
I];
4765 CB->getArgOperand(WrapperFunctionArgNo)->stripPointerCasts());
4767 Ctx,
"worker_state_machine.parallel_region.execute",
Kernel,
4768 StateMachineEndParallelBB);
4770 ->setDebugLoc(DLoc);
4776 Kernel, StateMachineEndParallelBB);
4777 A.registerManifestAddedBasicBlock(*PRExecuteBB);
4778 A.registerManifestAddedBasicBlock(*PRNextBB);
4783 if (
I + 1 <
E || !ReachedUnknownParallelRegions.empty()) {
4786 "worker.check_parallel_region", StateMachineIfCascadeCurrentBB);
4794 StateMachineIfCascadeCurrentBB)
4796 StateMachineIfCascadeCurrentBB = PRNextBB;
4802 if (!ReachedUnknownParallelRegions.empty()) {
4803 StateMachineIfCascadeCurrentBB->
setName(
4804 "worker_state_machine.parallel_region.fallback.execute");
4806 StateMachineIfCascadeCurrentBB)
4807 ->setDebugLoc(DLoc);
4810 StateMachineIfCascadeCurrentBB)
4813 FunctionCallee EndParallelFn =
4815 M, OMPRTL___kmpc_kernel_end_parallel);
4816 CallInst *EndParallel =
4818 OMPInfoCache.setCallingConvention(EndParallelFn, EndParallel);
4824 ->setDebugLoc(DLoc);
4834 KernelInfoState StateBefore = getState();
4840 struct UpdateKernelEnvCRAII {
4841 AAKernelInfoFunction &AA;
4843 UpdateKernelEnvCRAII(AAKernelInfoFunction &AA) : AA(AA) {}
4845 ~UpdateKernelEnvCRAII() {
4849 ConstantStruct *ExistingKernelEnvC =
4852 if (!AA.isValidState()) {
4853 AA.KernelEnvC = ExistingKernelEnvC;
4857 if (!AA.ReachedKnownParallelRegions.isValidState())
4858 AA.setUseGenericStateMachineOfKernelEnvironment(
4859 KernelInfo::getUseGenericStateMachineFromKernelEnvironment(
4860 ExistingKernelEnvC));
4862 if (!AA.SPMDCompatibilityTracker.isValidState())
4863 AA.setExecModeOfKernelEnvironment(
4864 KernelInfo::getExecModeFromKernelEnvironment(ExistingKernelEnvC));
4866 ConstantInt *MayUseNestedParallelismC =
4867 KernelInfo::getMayUseNestedParallelismFromKernelEnvironment(
4869 ConstantInt *NewMayUseNestedParallelismC = ConstantInt::get(
4870 MayUseNestedParallelismC->
getIntegerType(), AA.NestedParallelism);
4871 AA.setMayUseNestedParallelismOfKernelEnvironment(
4872 NewMayUseNestedParallelismC);
4882 if (!
I.mayWriteToMemory())
4885 const auto *UnderlyingObjsAA =
A.getAAFor<AAUnderlyingObjects>(
4887 DepClassTy::OPTIONAL);
4888 auto *
HS =
A.getAAFor<AAHeapToStack>(
4890 DepClassTy::OPTIONAL);
4891 if (UnderlyingObjsAA &&
4892 UnderlyingObjsAA->forallUnderlyingObjects([&](
Value &Obj) {
4893 if (AA::isAssumedThreadLocalObject(A, Obj, *this))
4897 auto *CB = dyn_cast<CallBase>(&Obj);
4898 return CB && HS && HS->isAssumedHeapToStack(*CB);
4904 SPMDCompatibilityTracker.insert(&
I);
4908 bool UsedAssumedInformationInCheckRWInst =
false;
4909 if (!SPMDCompatibilityTracker.isAtFixpoint())
4910 if (!
A.checkForAllReadWriteInstructions(
4911 CheckRWInst, *
this, UsedAssumedInformationInCheckRWInst))
4912 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
4914 bool UsedAssumedInformationFromReachingKernels =
false;
4915 if (!IsKernelEntry) {
4916 updateParallelLevels(
A);
4918 bool AllReachingKernelsKnown =
true;
4919 updateReachingKernelEntries(
A, AllReachingKernelsKnown);
4920 UsedAssumedInformationFromReachingKernels = !AllReachingKernelsKnown;
4922 if (!SPMDCompatibilityTracker.empty()) {
4923 if (!ParallelLevels.isValidState())
4924 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
4925 else if (!ReachingKernelEntries.isValidState())
4926 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
4932 for (
auto *
Kernel : ReachingKernelEntries) {
4933 auto *CBAA =
A.getAAFor<AAKernelInfo>(
4935 if (CBAA && CBAA->SPMDCompatibilityTracker.isValidState() &&
4936 CBAA->SPMDCompatibilityTracker.isAssumed())
4940 if (!CBAA || !CBAA->SPMDCompatibilityTracker.isAtFixpoint())
4941 UsedAssumedInformationFromReachingKernels =
true;
4943 if (SPMD != 0 &&
Generic != 0)
4944 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
4950 bool AllParallelRegionStatesWereFixed =
true;
4951 bool AllSPMDStatesWereFixed =
true;
4958 if (
Function *Callback = OMPInformationCache::getAnalyzableCallback(CB)) {
4960 <<
Callback->getName() <<
" of " << CB <<
"\n");
4961 if (
auto *CallbackAA =
A.getAAFor<AAKernelInfo>(
4963 getState() ^= CallbackAA->getState();
4964 AllSPMDStatesWereFixed &=
4965 CallbackAA->SPMDCompatibilityTracker.isAtFixpoint();
4966 AllParallelRegionStatesWereFixed &=
4967 CallbackAA->ReachedKnownParallelRegions.isAtFixpoint();
4968 AllParallelRegionStatesWereFixed &=
4969 CallbackAA->ReachedUnknownParallelRegions.isAtFixpoint();
4972 auto *CBAA =
A.getAAFor<AAKernelInfo>(
4976 getState() ^= CBAA->getState();
4977 AllSPMDStatesWereFixed &= CBAA->SPMDCompatibilityTracker.isAtFixpoint();
4978 AllParallelRegionStatesWereFixed &=
4979 CBAA->ReachedKnownParallelRegions.isAtFixpoint();
4980 AllParallelRegionStatesWereFixed &=
4981 CBAA->ReachedUnknownParallelRegions.isAtFixpoint();
4985 bool UsedAssumedInformationInCheckCallInst =
false;
4986 if (!
A.checkForAllCallLikeInstructions(
4987 CheckCallInst, *
this, UsedAssumedInformationInCheckCallInst)) {
4989 <<
"Failed to visit all call-like instructions!\n";);
4990 return indicatePessimisticFixpoint();
4995 if (!UsedAssumedInformationInCheckCallInst &&
4996 AllParallelRegionStatesWereFixed) {
4997 ReachedKnownParallelRegions.indicateOptimisticFixpoint();
4998 ReachedUnknownParallelRegions.indicateOptimisticFixpoint();
5003 if (!UsedAssumedInformationInCheckRWInst &&
5004 !UsedAssumedInformationInCheckCallInst &&
5005 !UsedAssumedInformationFromReachingKernels && AllSPMDStatesWereFixed)
5006 SPMDCompatibilityTracker.indicateOptimisticFixpoint();
5008 return StateBefore == getState() ? ChangeStatus::UNCHANGED
5009 : ChangeStatus::CHANGED;
5014 void updateReachingKernelEntries(Attributor &
A,
5015 bool &AllReachingKernelsKnown) {
5016 auto PredCallSite = [&](AbstractCallSite ACS) {
5019 assert(Caller &&
"Caller is nullptr");
5021 auto *CAA =
A.getOrCreateAAFor<AAKernelInfo>(
5023 if (CAA && CAA->ReachingKernelEntries.isValidState()) {
5024 ReachingKernelEntries ^= CAA->ReachingKernelEntries;
5030 ReachingKernelEntries.indicatePessimisticFixpoint();
5035 if (!
A.checkForAllCallSites(PredCallSite, *
this,
5037 AllReachingKernelsKnown))
5038 ReachingKernelEntries.indicatePessimisticFixpoint();
5042 void updateParallelLevels(Attributor &
A) {
5043 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
5044 OMPInformationCache::RuntimeFunctionInfo &Parallel60RFI =
5045 OMPInfoCache.RFIs[OMPRTL___kmpc_parallel_60];
5047 auto PredCallSite = [&](AbstractCallSite ACS) {
5050 assert(Caller &&
"Caller is nullptr");
5054 if (CAA && CAA->ParallelLevels.isValidState()) {
5060 if (Caller == Parallel60RFI.Declaration) {
5061 ParallelLevels.indicatePessimisticFixpoint();
5065 ParallelLevels ^= CAA->ParallelLevels;
5072 ParallelLevels.indicatePessimisticFixpoint();
5077 bool AllCallSitesKnown =
true;
5078 if (!
A.checkForAllCallSites(PredCallSite, *
this,
5081 ParallelLevels.indicatePessimisticFixpoint();
5088struct AAKernelInfoCallSite : AAKernelInfo {
5089 AAKernelInfoCallSite(
const IRPosition &IRP, Attributor &
A)
5090 : AAKernelInfo(IRP,
A) {}
5094 AAKernelInfo::initialize(
A);
5097 auto *AssumptionAA =
A.getAAFor<AAAssumptionInfo>(
5101 if (AssumptionAA && AssumptionAA->hasAssumption(
"ompx_spmd_amenable")) {
5102 indicateOptimisticFixpoint();
5110 indicateOptimisticFixpoint();
5119 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
5120 const auto &It = OMPInfoCache.RuntimeFunctionIDMap.find(Callee);
5121 if (It == OMPInfoCache.RuntimeFunctionIDMap.end()) {
5123 if (!Callee || !
A.isFunctionIPOAmendable(*Callee)) {
5127 if (!AssumptionAA ||
5128 !(AssumptionAA->hasAssumption(
"omp_no_openmp") ||
5129 AssumptionAA->hasAssumption(
"omp_no_parallelism")))
5130 ReachedUnknownParallelRegions.insert(&CB);
5134 if (!SPMDCompatibilityTracker.isAtFixpoint()) {
5135 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5136 SPMDCompatibilityTracker.insert(&CB);
5141 indicateOptimisticFixpoint();
5150 if (NumCallees > 1 && !
Callee->hasMetadata(LLVMContext::MD_callback)) {
5151 indicatePessimisticFixpoint();
5158 case OMPRTL___kmpc_is_spmd_exec_mode:
5159 case OMPRTL___kmpc_distribute_static_fini:
5160 case OMPRTL___kmpc_for_static_fini:
5161 case OMPRTL___kmpc_global_thread_num:
5162 case OMPRTL___kmpc_get_hardware_num_threads_in_block:
5163 case OMPRTL___kmpc_get_hardware_num_blocks:
5164 case OMPRTL___kmpc_single:
5165 case OMPRTL___kmpc_end_single:
5166 case OMPRTL___kmpc_master:
5167 case OMPRTL___kmpc_end_master:
5168 case OMPRTL___kmpc_barrier:
5169 case OMPRTL___kmpc_nvptx_parallel_reduce_nowait_v2:
5170 case OMPRTL___kmpc_gpu_xteam_reduce_nowait:
5171 case OMPRTL___kmpc_error:
5172 case OMPRTL___kmpc_flush:
5173 case OMPRTL___kmpc_get_hardware_thread_id_in_block:
5174 case OMPRTL___kmpc_get_warp_size:
5175 case OMPRTL_omp_get_thread_num:
5176 case OMPRTL_omp_get_num_threads:
5177 case OMPRTL_omp_get_max_threads:
5178 case OMPRTL_omp_in_parallel:
5179 case OMPRTL_omp_get_dynamic:
5180 case OMPRTL_omp_get_cancellation:
5181 case OMPRTL_omp_get_nested:
5182 case OMPRTL_omp_get_schedule:
5183 case OMPRTL_omp_get_thread_limit:
5184 case OMPRTL_omp_get_supported_active_levels:
5185 case OMPRTL_omp_get_max_active_levels:
5186 case OMPRTL_omp_get_level:
5187 case OMPRTL_omp_get_ancestor_thread_num:
5188 case OMPRTL_omp_get_team_size:
5189 case OMPRTL_omp_get_active_level:
5190 case OMPRTL_omp_in_final:
5191 case OMPRTL_omp_get_proc_bind:
5192 case OMPRTL_omp_get_num_places:
5193 case OMPRTL_omp_get_num_procs:
5194 case OMPRTL_omp_get_place_proc_ids:
5195 case OMPRTL_omp_get_place_num:
5196 case OMPRTL_omp_get_partition_num_places:
5197 case OMPRTL_omp_get_partition_place_nums:
5198 case OMPRTL_omp_get_wtime:
5200 case OMPRTL___kmpc_distribute_static_init_4:
5201 case OMPRTL___kmpc_distribute_static_init_4u:
5202 case OMPRTL___kmpc_distribute_static_init_8:
5203 case OMPRTL___kmpc_distribute_static_init_8u:
5204 case OMPRTL___kmpc_for_static_init_4:
5205 case OMPRTL___kmpc_for_static_init_4u:
5206 case OMPRTL___kmpc_for_static_init_8:
5207 case OMPRTL___kmpc_for_static_init_8u: {
5209 unsigned ScheduleArgOpNo = 2;
5210 auto *ScheduleTypeCI =
5212 unsigned ScheduleTypeVal =
5213 ScheduleTypeCI ? ScheduleTypeCI->getZExtValue() : 0;
5215 case OMPScheduleType::UnorderedStatic:
5216 case OMPScheduleType::UnorderedStaticChunked:
5217 case OMPScheduleType::OrderedDistribute:
5218 case OMPScheduleType::OrderedDistributeChunked:
5221 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5222 SPMDCompatibilityTracker.insert(&CB);
5226 case OMPRTL___kmpc_target_init:
5229 case OMPRTL___kmpc_target_deinit:
5230 KernelDeinitCB = &CB;
5232 case OMPRTL___kmpc_parallel_60:
5233 if (!handleParallel60(
A, CB))
5234 indicatePessimisticFixpoint();
5236 case OMPRTL___kmpc_omp_task:
5238 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5239 SPMDCompatibilityTracker.insert(&CB);
5240 ReachedUnknownParallelRegions.insert(&CB);
5242 case OMPRTL___kmpc_alloc_shared:
5243 case OMPRTL___kmpc_free_shared:
5251 case OMPRTL___kmpc_distribute_static_loop_4:
5252 case OMPRTL___kmpc_distribute_static_loop_4u:
5253 case OMPRTL___kmpc_distribute_static_loop_8:
5254 case OMPRTL___kmpc_distribute_static_loop_8u:
5262 if (!OMPInformationCache::getAnalyzableCallback(CB))
5263 ReachedUnknownParallelRegions.insert(&CB);
5264 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5265 SPMDCompatibilityTracker.insert(&CB);
5267 case OMPRTL___kmpc_distribute_for_static_loop_4:
5268 case OMPRTL___kmpc_distribute_for_static_loop_4u:
5269 case OMPRTL___kmpc_distribute_for_static_loop_8:
5270 case OMPRTL___kmpc_distribute_for_static_loop_8u:
5271 case OMPRTL___kmpc_for_static_loop_4:
5272 case OMPRTL___kmpc_for_static_loop_4u:
5273 case OMPRTL___kmpc_for_static_loop_8:
5274 case OMPRTL___kmpc_for_static_loop_8u:
5283 if (!OMPInformationCache::getAnalyzableCallback(CB))
5284 ReachedUnknownParallelRegions.insert(&CB);
5285 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5286 SPMDCompatibilityTracker.insert(&CB);
5291 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5292 SPMDCompatibilityTracker.insert(&CB);
5298 indicateOptimisticFixpoint();
5302 A.getAAFor<AACallEdges>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
5303 if (!AACE || !AACE->getState().isValidState() || AACE->hasUnknownCallee()) {
5304 CheckCallee(getAssociatedFunction(), 1);
5307 const auto &OptimisticEdges = AACE->getOptimisticEdges();
5308 for (
auto *Callee : OptimisticEdges) {
5309 CheckCallee(Callee, OptimisticEdges.size());
5320 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
5321 KernelInfoState StateBefore = getState();
5323 auto CheckCallee = [&](
Function *
F,
int NumCallees) {
5324 const auto &It = OMPInfoCache.RuntimeFunctionIDMap.find(
F);
5328 if (It == OMPInfoCache.RuntimeFunctionIDMap.end()) {
5331 A.getAAFor<AAKernelInfo>(*
this, FnPos, DepClassTy::REQUIRED);
5333 return indicatePessimisticFixpoint();
5334 if (getState() == FnAA->getState())
5335 return ChangeStatus::UNCHANGED;
5336 getState() = FnAA->getState();
5337 return ChangeStatus::CHANGED;
5341 if (NumCallees > 1 && !
F->hasMetadata(LLVMContext::MD_callback))
5342 return indicatePessimisticFixpoint();
5345 if (It->getSecond() == OMPRTL___kmpc_parallel_60) {
5346 if (!handleParallel60(
A, CB))
5347 return indicatePessimisticFixpoint();
5348 return StateBefore == getState() ? ChangeStatus::UNCHANGED
5349 : ChangeStatus::CHANGED;
5355 (It->getSecond() == OMPRTL___kmpc_alloc_shared ||
5356 It->getSecond() == OMPRTL___kmpc_free_shared) &&
5357 "Expected a __kmpc_alloc_shared or __kmpc_free_shared runtime call");
5359 auto *HeapToStackAA =
A.getAAFor<AAHeapToStack>(
5361 auto *HeapToSharedAA =
A.getAAFor<AAHeapToShared>(
5369 case OMPRTL___kmpc_alloc_shared:
5370 if ((!HeapToStackAA || !HeapToStackAA->isAssumedHeapToStack(CB)) &&
5371 (!HeapToSharedAA || !HeapToSharedAA->isAssumedHeapToShared(CB)))
5372 SPMDCompatibilityTracker.insert(&CB);
5374 case OMPRTL___kmpc_free_shared:
5375 if ((!HeapToStackAA ||
5376 !HeapToStackAA->isAssumedHeapToStackRemovedFree(CB)) &&
5378 !HeapToSharedAA->isAssumedHeapToSharedRemovedFree(CB)))
5379 SPMDCompatibilityTracker.insert(&CB);
5382 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5383 SPMDCompatibilityTracker.insert(&CB);
5385 return ChangeStatus::CHANGED;
5389 A.getAAFor<AACallEdges>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
5390 if (!AACE || !AACE->getState().isValidState() || AACE->hasUnknownCallee()) {
5391 if (
Function *
F = getAssociatedFunction())
5394 const auto &OptimisticEdges = AACE->getOptimisticEdges();
5395 for (
auto *Callee : OptimisticEdges) {
5396 CheckCallee(Callee, OptimisticEdges.size());
5402 return StateBefore == getState() ? ChangeStatus::UNCHANGED
5403 : ChangeStatus::CHANGED;
5408 bool handleParallel60(Attributor &
A, CallBase &CB) {
5409 const unsigned int NonWrapperFunctionArgNo = 5;
5410 const unsigned int WrapperFunctionArgNo = 6;
5411 auto ParallelRegionOpArgNo = SPMDCompatibilityTracker.isAssumed()
5412 ? NonWrapperFunctionArgNo
5413 : WrapperFunctionArgNo;
5417 if (!ParallelRegion)
5420 ReachedKnownParallelRegions.insert(&CB);
5422 auto *FnAA =
A.getAAFor<AAKernelInfo>(
5424 NestedParallelism |= !FnAA || !FnAA->getState().isValidState() ||
5425 !FnAA->ReachedKnownParallelRegions.empty() ||
5426 !FnAA->ReachedKnownParallelRegions.isValidState() ||
5427 !FnAA->ReachedUnknownParallelRegions.isValidState() ||
5428 !FnAA->ReachedUnknownParallelRegions.empty();
5433struct AAFoldRuntimeCall
5434 :
public StateWrapper<BooleanState, AbstractAttribute> {
5435 using Base = StateWrapper<BooleanState, AbstractAttribute>;
5437 AAFoldRuntimeCall(
const IRPosition &IRP, Attributor &
A) :
Base(IRP) {}
5440 void trackStatistics()
const override {}
5443 static AAFoldRuntimeCall &createForPosition(
const IRPosition &IRP,
5447 StringRef
getName()
const override {
return "AAFoldRuntimeCall"; }
5450 const char *getIdAddr()
const override {
return &ID; }
5454 static bool classof(
const AbstractAttribute *AA) {
5458 static const char ID;
5461struct AAFoldRuntimeCallCallSiteReturned : AAFoldRuntimeCall {
5462 AAFoldRuntimeCallCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5463 : AAFoldRuntimeCall(IRP,
A) {}
5466 const std::string getAsStr(Attributor *)
const override {
5467 if (!isValidState())
5470 std::string Str(
"simplified value: ");
5472 if (!SimplifiedValue)
5473 return Str + std::string(
"none");
5475 if (!*SimplifiedValue)
5476 return Str + std::string(
"nullptr");
5479 return Str + std::to_string(CI->getSExtValue());
5481 return Str + std::string(
"unknown");
5486 indicatePessimisticFixpoint();
5490 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
5491 const auto &It = OMPInfoCache.RuntimeFunctionIDMap.find(Callee);
5492 assert(It != OMPInfoCache.RuntimeFunctionIDMap.end() &&
5493 "Expected a known OpenMP runtime function");
5495 RFKind = It->getSecond();
5498 A.registerSimplificationCallback(
5500 [&](
const IRPosition &IRP,
const AbstractAttribute *AA,
5501 bool &UsedAssumedInformation) -> std::optional<Value *> {
5502 assert((isValidState() || SimplifiedValue ==
nullptr) &&
5503 "Unexpected invalid state!");
5505 if (!isAtFixpoint()) {
5506 UsedAssumedInformation =
true;
5508 A.recordDependence(*
this, *AA, DepClassTy::OPTIONAL);
5510 return SimplifiedValue;
5517 case OMPRTL___kmpc_is_spmd_exec_mode:
5520 case OMPRTL___kmpc_parallel_level:
5523 case OMPRTL___kmpc_get_hardware_num_threads_in_block:
5524 Changed =
Changed | foldKernelFnAttribute(
A,
"omp_target_thread_limit");
5526 case OMPRTL___kmpc_get_hardware_num_blocks:
5539 if (SimplifiedValue && *SimplifiedValue) {
5542 A.deleteAfterManifest(
I);
5545 auto Remark = [&](OptimizationRemark
OR) {
5547 return OR <<
"Replacing OpenMP runtime call "
5549 <<
ore::NV(
"FoldedValue",
C->getZExtValue()) <<
".";
5550 return OR <<
"Replacing OpenMP runtime call "
5555 A.emitRemark<OptimizationRemark>(CB,
"OMP180",
Remark);
5558 << **SimplifiedValue <<
"\n");
5560 Changed = ChangeStatus::CHANGED;
5567 SimplifiedValue =
nullptr;
5568 return AAFoldRuntimeCall::indicatePessimisticFixpoint();
5574 std::optional<Value *> SimplifiedValueBefore = SimplifiedValue;
5576 unsigned AssumedSPMDCount = 0, KnownSPMDCount = 0;
5577 unsigned AssumedNonSPMDCount = 0, KnownNonSPMDCount = 0;
5578 auto *CallerKernelInfoAA =
A.getAAFor<AAKernelInfo>(
5581 if (!CallerKernelInfoAA ||
5582 !CallerKernelInfoAA->ReachingKernelEntries.isValidState())
5583 return indicatePessimisticFixpoint();
5585 for (
Kernel K : CallerKernelInfoAA->ReachingKernelEntries) {
5587 DepClassTy::REQUIRED);
5589 if (!AA || !AA->isValidState()) {
5590 SimplifiedValue =
nullptr;
5591 return indicatePessimisticFixpoint();
5594 if (AA->SPMDCompatibilityTracker.isAssumed()) {
5595 if (AA->SPMDCompatibilityTracker.isAtFixpoint())
5600 if (AA->SPMDCompatibilityTracker.isAtFixpoint())
5601 ++KnownNonSPMDCount;
5603 ++AssumedNonSPMDCount;
5607 if ((AssumedSPMDCount + KnownSPMDCount) &&
5608 (AssumedNonSPMDCount + KnownNonSPMDCount))
5609 return indicatePessimisticFixpoint();
5611 auto &Ctx = getAnchorValue().getContext();
5612 if (KnownSPMDCount || AssumedSPMDCount) {
5613 assert(KnownNonSPMDCount == 0 && AssumedNonSPMDCount == 0 &&
5614 "Expected only SPMD kernels!");
5617 SimplifiedValue = ConstantInt::get(Type::getInt8Ty(Ctx),
true);
5618 }
else if (KnownNonSPMDCount || AssumedNonSPMDCount) {
5619 assert(KnownSPMDCount == 0 && AssumedSPMDCount == 0 &&
5620 "Expected only non-SPMD kernels!");
5623 SimplifiedValue = ConstantInt::get(Type::getInt8Ty(Ctx),
false);
5628 assert(!SimplifiedValue &&
"SimplifiedValue should be none");
5631 return SimplifiedValue == SimplifiedValueBefore ? ChangeStatus::UNCHANGED
5632 : ChangeStatus::CHANGED;
5637 std::optional<Value *> SimplifiedValueBefore = SimplifiedValue;
5639 auto *CallerKernelInfoAA =
A.getAAFor<AAKernelInfo>(
5642 if (!CallerKernelInfoAA ||
5643 !CallerKernelInfoAA->ParallelLevels.isValidState())
5644 return indicatePessimisticFixpoint();
5646 if (!CallerKernelInfoAA->ReachingKernelEntries.isValidState())
5647 return indicatePessimisticFixpoint();
5649 if (CallerKernelInfoAA->ReachingKernelEntries.empty()) {
5650 assert(!SimplifiedValue &&
5651 "SimplifiedValue should keep none at this point");
5652 return ChangeStatus::UNCHANGED;
5655 unsigned AssumedSPMDCount = 0, KnownSPMDCount = 0;
5656 unsigned AssumedNonSPMDCount = 0, KnownNonSPMDCount = 0;
5657 for (
Kernel K : CallerKernelInfoAA->ReachingKernelEntries) {
5659 DepClassTy::REQUIRED);
5660 if (!AA || !AA->SPMDCompatibilityTracker.isValidState())
5661 return indicatePessimisticFixpoint();
5663 if (AA->SPMDCompatibilityTracker.isAssumed()) {
5664 if (AA->SPMDCompatibilityTracker.isAtFixpoint())
5669 if (AA->SPMDCompatibilityTracker.isAtFixpoint())
5670 ++KnownNonSPMDCount;
5672 ++AssumedNonSPMDCount;
5676 if ((AssumedSPMDCount + KnownSPMDCount) &&
5677 (AssumedNonSPMDCount + KnownNonSPMDCount))
5678 return indicatePessimisticFixpoint();
5680 auto &Ctx = getAnchorValue().getContext();
5684 if (AssumedSPMDCount || KnownSPMDCount) {
5685 assert(KnownNonSPMDCount == 0 && AssumedNonSPMDCount == 0 &&
5686 "Expected only SPMD kernels!");
5687 SimplifiedValue = ConstantInt::get(Type::getInt8Ty(Ctx), 1);
5689 assert(KnownSPMDCount == 0 && AssumedSPMDCount == 0 &&
5690 "Expected only non-SPMD kernels!");
5691 SimplifiedValue = ConstantInt::get(Type::getInt8Ty(Ctx), 0);
5693 return SimplifiedValue == SimplifiedValueBefore ? ChangeStatus::UNCHANGED
5694 : ChangeStatus::CHANGED;
5697 ChangeStatus foldKernelFnAttribute(Attributor &
A, llvm::StringRef Attr) {
5699 int32_t CurrentAttrValue = -1;
5700 std::optional<Value *> SimplifiedValueBefore = SimplifiedValue;
5702 auto *CallerKernelInfoAA =
A.getAAFor<AAKernelInfo>(
5705 if (!CallerKernelInfoAA ||
5706 !CallerKernelInfoAA->ReachingKernelEntries.isValidState())
5707 return indicatePessimisticFixpoint();
5710 for (
Kernel K : CallerKernelInfoAA->ReachingKernelEntries) {
5711 int32_t NextAttrVal =
K->getFnAttributeAsParsedInteger(Attr, -1);
5713 if (NextAttrVal == -1 ||
5714 (CurrentAttrValue != -1 && CurrentAttrValue != NextAttrVal))
5715 return indicatePessimisticFixpoint();
5716 CurrentAttrValue = NextAttrVal;
5719 if (CurrentAttrValue != -1) {
5720 auto &Ctx = getAnchorValue().getContext();
5722 ConstantInt::get(Type::getInt32Ty(Ctx), CurrentAttrValue);
5724 return SimplifiedValue == SimplifiedValueBefore ? ChangeStatus::UNCHANGED
5725 : ChangeStatus::CHANGED;
5731 std::optional<Value *> SimplifiedValue;
5741 auto &RFI = OMPInfoCache.RFIs[RF];
5742 RFI.foreachUse(SCC, [&](Use &U,
Function &
F) {
5743 CallInst *CI = OpenMPOpt::getCallIfRegularCall(U, &RFI);
5746 A.getOrCreateAAFor<AAFoldRuntimeCall>(
5748 DepClassTy::NONE,
false,
5754void OpenMPOpt::registerAAs(
bool IsModulePass) {
5764 A.getOrCreateAAFor<AAKernelInfo>(
5766 DepClassTy::NONE,
false,
5770 OMPInformationCache::RuntimeFunctionInfo &InitRFI =
5771 OMPInfoCache.RFIs[OMPRTL___kmpc_target_init];
5772 InitRFI.foreachUse(SCC, CreateKernelInfoCB);
5774 registerFoldRuntimeCall(OMPRTL___kmpc_is_spmd_exec_mode);
5775 registerFoldRuntimeCall(OMPRTL___kmpc_parallel_level);
5776 registerFoldRuntimeCall(OMPRTL___kmpc_get_hardware_num_threads_in_block);
5777 registerFoldRuntimeCall(OMPRTL___kmpc_get_hardware_num_blocks);
5782 for (
int Idx = 0;
Idx < OMPInfoCache.ICVs.size() - 1; ++
Idx) {
5785 auto &GetterRFI = OMPInfoCache.RFIs[ICVInfo.Getter];
5788 CallInst *CI = OpenMPOpt::getCallIfRegularCall(U, &GetterRFI);
5795 A.getOrCreateAAFor<AAICVTracker>(CBPos);
5799 GetterRFI.foreachUse(SCC, CreateAA);
5808 for (
auto *
F : SCC) {
5809 if (
F->isDeclaration())
5815 if (
F->hasLocalLinkage()) {
5817 const auto *CB = dyn_cast<CallBase>(U.getUser());
5818 return CB && CB->isCallee(&U) &&
5819 A.isRunOn(const_cast<Function *>(CB->getCaller()));
5823 registerAAsForFunction(
A, *
F);
5827void OpenMPOpt::registerAAsForFunction(Attributor &
A,
const Function &
F) {
5828 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
5831 A.getOrCreateAAFor<AAExecutionDomain>(FPos);
5832 if (
F.hasFnAttribute(Attribute::Convergent))
5833 A.getOrCreateAAFor<AANonConvergent>(FPos);
5835 bool FunctionUsesSharedAlloc =
false;
5837 const OMPInformationCache::RuntimeFunctionInfo::UseVector *SharedAllocUses =
5838 OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared].getUseVector(
5840 FunctionUsesSharedAlloc = SharedAllocUses && !SharedAllocUses->
empty();
5842 bool HasHeapToStackCandidate =
false;
5843 const TargetLibraryInfo *TLI =
nullptr;
5847 bool UsedAssumedInformation =
false;
5850 A.getOrCreateAAFor<AAAddressSpace>(
5857 TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(
F);
5858 HasHeapToStackCandidate =
5862 A.getOrCreateAAFor<AAIndirectCallInfo>(
5867 A.getOrCreateAAFor<AAAddressSpace>(
5876 if (
II->getIntrinsicID() == Intrinsic::assume) {
5877 A.getOrCreateAAFor<AAPotentialValues>(
5884 if (FunctionUsesSharedAlloc)
5885 A.getOrCreateAAFor<AAHeapToShared>(FPos);
5886 if (HasHeapToStackCandidate)
5887 A.getOrCreateAAFor<AAHeapToStack>(FPos);
5890const char AAICVTracker::ID = 0;
5891const char AAKernelInfo::ID = 0;
5893const char AAHeapToShared::ID = 0;
5894const char AAFoldRuntimeCall::ID = 0;
5896AAICVTracker &AAICVTracker::createForPosition(
const IRPosition &IRP,
5898 AAICVTracker *AA =
nullptr;
5906 AA =
new (
A.Allocator) AAICVTrackerFunctionReturned(IRP,
A);
5909 AA =
new (
A.Allocator) AAICVTrackerCallSiteReturned(IRP,
A);
5912 AA =
new (
A.Allocator) AAICVTrackerCallSite(IRP,
A);
5915 AA =
new (
A.Allocator) AAICVTrackerFunction(IRP,
A);
5924 AAExecutionDomainFunction *
AA =
nullptr;
5934 "AAExecutionDomain can only be created for function position!");
5936 AA =
new (
A.Allocator) AAExecutionDomainFunction(IRP,
A);
5943AAHeapToShared &AAHeapToShared::createForPosition(
const IRPosition &IRP,
5945 AAHeapToSharedFunction *
AA =
nullptr;
5955 "AAHeapToShared can only be created for function position!");
5957 AA =
new (
A.Allocator) AAHeapToSharedFunction(IRP,
A);
5964AAKernelInfo &AAKernelInfo::createForPosition(
const IRPosition &IRP,
5966 AAKernelInfo *AA =
nullptr;
5976 AA =
new (
A.Allocator) AAKernelInfoCallSite(IRP,
A);
5979 AA =
new (
A.Allocator) AAKernelInfoFunction(IRP,
A);
5986AAFoldRuntimeCall &AAFoldRuntimeCall::createForPosition(
const IRPosition &IRP,
5988 AAFoldRuntimeCall *AA =
nullptr;
5997 llvm_unreachable(
"KernelInfo can only be created for call site position!");
5999 AA =
new (
A.Allocator) AAFoldRuntimeCallCallSiteReturned(IRP,
A);
6019 unsigned NumAssumedCallees) {
6037 if (Kernels.contains(&
F))
6039 return !
F.use_empty();
6046 return ORA <<
"Could not internalize function. "
6047 <<
"Some optimizations may not be possible. [OMP140]";
6059 if (!
F.isDeclaration() && !Kernels.contains(&
F) && IsCalled(
F) &&
6063 }
else if (!
F.hasLocalLinkage() && !
F.hasFnAttribute(Attribute::Cold)) {
6076 if (!
F.isDeclaration() && !InternalizedMap.
lookup(&
F)) {
6078 Functions.insert(&
F);
6096 OMPInformationCache InfoCache(M, AG, Allocator,
nullptr, PostLink);
6098 unsigned MaxFixpointIterations =
6111 return F.hasFnAttribute(
"kernel");
6116 OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache,
A);
6122 if (!
F.isDeclaration() && !Kernels.contains(&
F) &&
6123 !
F.hasFnAttribute(Attribute::NoInline))
6124 F.addFnAttr(Attribute::AlwaysInline);
6154 Module &M = *
C.begin()->getFunction().getParent();
6176 OMPInformationCache InfoCache(*(Functions.back()->getParent()), AG, Allocator,
6177 &Functions, PostLink);
6179 unsigned MaxFixpointIterations =
6194 OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache,
A);
6195 bool Changed = OMPOpt.run(
false);
6214 if (
F.hasKernelCallingConv()) {
6219 ++NumOpenMPTargetRegionKernels;
6222 ++NumNonOpenMPTargetRegionKernels;
6229 Metadata *MD = M.getModuleFlag(
"openmp");
6237 Metadata *MD = M.getModuleFlag(
"openmp-device");
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
amdgpu aa AMDGPU Address space based Alias Analysis Wrapper
amdgpu next use AMDGPU Next Use Analysis Printer
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
static cl::opt< unsigned > SetFixpointIterations("attributor-max-iterations", cl::Hidden, cl::desc("Maximal number of fixpoint iterations."), cl::init(32))
static const Function * getParent(const Value *V)
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")
This file provides interfaces used to manipulate a call graph, regardless if it is a "old style" Call...
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...
This file defines the DenseSet and SmallDenseSet classes.
This file defines an array type that can be indexed using scoped enum values.
static void emitRemark(const Function &F, OptimizationRemarkEmitter &ORE, bool Skip)
Loop::LoopBounds::Direction Direction
Machine Check Debug Module
This file provides utility analysis objects describing memory locations.
uint64_t IntrinsicInst * II
This file defines constans and helpers used when dealing with OpenMP.
This file defines constans that will be used by both host and device compilation.
static constexpr auto TAG
static cl::opt< bool > HideMemoryTransferLatency("openmp-hide-memory-transfer-latency", cl::desc("[WIP] Tries to hide the latency of host to device memory" " transfers"), cl::Hidden, cl::init(false))
static cl::opt< bool > DisableOpenMPOptStateMachineRewrite("openmp-opt-disable-state-machine-rewrite", cl::desc("Disable OpenMP optimizations that replace the state machine."), cl::Hidden, cl::init(false))
static cl::opt< bool > EnableParallelRegionMerging("openmp-opt-enable-merging", cl::desc("Enable the OpenMP region merging optimization."), cl::Hidden, cl::init(false))
static cl::opt< bool > PrintModuleAfterOptimizations("openmp-opt-print-module-after", cl::desc("Print the current module after OpenMP optimizations."), cl::Hidden, cl::init(false))
#define KERNEL_ENVIRONMENT_CONFIGURATION_GETTER(MEMBER)
#define KERNEL_ENVIRONMENT_CONFIGURATION_IDX(MEMBER, IDX)
#define KERNEL_ENVIRONMENT_CONFIGURATION_SETTER(MEMBER)
static cl::opt< bool > PrintOpenMPKernels("openmp-print-gpu-kernels", cl::init(false), cl::Hidden)
static cl::opt< bool > DisableOpenMPOptFolding("openmp-opt-disable-folding", cl::desc("Disable OpenMP optimizations involving folding."), cl::Hidden, cl::init(false))
static bool shouldSpecializeIndirectCallee(Attributor &, const AbstractAttribute &, CallBase &, Function &, unsigned NumAssumedCallees)
Bound the if-cascade AAIndirectCallInfo builds for an indirect call.
static cl::opt< bool > PrintModuleBeforeOptimizations("openmp-opt-print-module-before", cl::desc("Print the current module before OpenMP optimizations."), cl::Hidden, cl::init(false))
static cl::opt< unsigned > SetFixpointIterations("openmp-opt-max-iterations", cl::Hidden, cl::desc("Maximal number of attributor iterations."), cl::init(256))
static cl::opt< bool > DisableInternalization("openmp-opt-disable-internalization", cl::desc("Disable function internalization."), cl::Hidden, cl::init(false))
static cl::opt< bool > PrintICVValues("openmp-print-icv-values", cl::init(false), cl::Hidden)
static cl::opt< bool > DisableOpenMPOptimizations("openmp-opt-disable", cl::desc("Disable OpenMP specific optimizations."), cl::Hidden, cl::init(false))
static cl::opt< unsigned > SharedMemoryLimit("openmp-opt-shared-limit", cl::Hidden, cl::desc("Maximum amount of shared memory to use."), cl::init(std::numeric_limits< unsigned >::max()))
static cl::opt< bool > EnableVerboseRemarks("openmp-opt-verbose-remarks", cl::desc("Enables more verbose remarks."), cl::Hidden, cl::init(false))
static cl::opt< unsigned > MaxCalleesForSpecialization("openmp-opt-max-callees-for-specialization", cl::Hidden, cl::desc("Number of possible callees above which an indirect call site is " "left alone rather than specialized into an if-cascade."), cl::init(3))
static cl::opt< bool > DisableOpenMPOptDeglobalization("openmp-opt-disable-deglobalization", cl::desc("Disable OpenMP optimizations involving deglobalization."), cl::Hidden, cl::init(false))
static cl::opt< bool > DisableOpenMPOptBarrierElimination("openmp-opt-disable-barrier-elimination", cl::desc("Disable OpenMP optimizations that eliminate barriers."), cl::Hidden, cl::init(false))
static cl::opt< bool > DeduceICVValues("openmp-deduce-icv-values", cl::init(false), cl::Hidden)
#define KERNEL_ENVIRONMENT_IDX(MEMBER, IDX)
#define KERNEL_ENVIRONMENT_GETTER(MEMBER, RETURNTYPE)
static cl::opt< bool > DisableOpenMPOptSPMDization("openmp-opt-disable-spmdization", cl::desc("Disable OpenMP optimizations involving SPMD-ization."), cl::Hidden, cl::init(false))
static cl::opt< bool > AlwaysInlineDeviceFunctions("openmp-opt-inline-device", cl::desc("Inline all applicable functions on the device."), cl::Hidden, cl::init(false))
FunctionAnalysisManager FAM
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
This file contains the declarations for profiling metadata utility functions.
static StringRef getName(Value *V)
Remove Loads Into Fake Uses
std::pair< BasicBlock *, BasicBlock * > Edge
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T, const llvm::StringTable &StandardNames, VectorLibrary VecLib)
Initialize the set of available library functions based on the specified target triple.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
iterator begin()
Instruction iterator methods.
LLVM_ABI const_iterator getFirstInsertionPt() const
Returns an iterator to the first instruction in this block that is suitable for inserting a non-PHI i...
LLVM_ABI BasicBlock * splitBasicBlock(iterator I, const Twine &BBName="")
Split the basic block into two basic blocks at the specified instruction.
const Function * getParent() const
Return the enclosing method, or null if none.
reverse_iterator rbegin()
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
LLVM_ABI const BasicBlock * getUniqueSuccessor() const
Return the successor of this block if it has a unique successor.
InstListType::reverse_iterator reverse_iterator
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
void setCallingConv(CallingConv::ID CC)
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
bool doesNotAccessMemory(unsigned OpNo) const
bool hasFnAttr(Attribute::AttrKind Kind) const
Determine whether this call has the given attribute.
LLVM_ABI bool isIndirectCall() const
Return true if the callsite is an indirect call.
bool isCallee(Value::const_user_iterator UI) const
Determine whether the passed iterator points to the callee operand's Use.
Value * getCalledOperand() const
Value * getArgOperand(unsigned i) const
void setArgOperand(unsigned i, Value *v)
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
unsigned getArgOperandNo(const Use *U) const
Given a use for a arg operand, get the arg operand number that corresponds to it.
unsigned arg_size() const
AttributeList getAttributes() const
Return the attributes for this call.
void addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind)
Adds the attribute to the indicated argument.
bool isArgOperand(const Use *U) const
bool hasOperandBundles() const
Return true if this User has any operand bundles.
LLVM_ABI Function * getCaller()
Helper to get the caller (the parent function).
Wrapper to unify "old style" CallGraph and "new style" LazyCallGraph.
void initialize(LazyCallGraph &LCG, LazyCallGraph::SCC &SCC, CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR)
Initializers for usage outside of a CGSCC pass, inside a CGSCC pass in the old and new pass manager (...
This class represents a function call, abstracting a target machine's calling convention.
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
@ ICMP_SLT
signed less than
static CondBrInst * Create(Value *Cond, BasicBlock *IfTrue, BasicBlock *IfFalse, InsertPosition InsertBefore=nullptr)
static LLVM_ABI Constant * getPointerCast(Constant *C, Type *Ty)
Create a BitCast, AddrSpaceCast, or a PtrToInt cast constant expression.
static LLVM_ABI Constant * getPointerBitCastOrAddrSpaceCast(Constant *C, Type *Ty)
Create a BitCast or AddrSpaceCast for a pointer type depending on the address space.
This is the shared class of boolean and integer constants.
IntegerType * getIntegerType() const
Variant of the getType() method to always return an IntegerType, which reduces the amount of casting ...
static LLVM_ABI ConstantInt * getTrue(LLVMContext &Context)
bool isZero() const
This is just a convenience method to make client code smaller for a common code.
int64_t getSExtValue() const
Return the constant as a 64-bit integer value after it has been sign extended as appropriate for the ...
static LLVM_ABI ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
This is an important base class in LLVM.
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
ValueT lookup(const_arg_type_t< KeyT > Val) const
Return the entry for the specified key, or a default constructed value if no such entry exists.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
LLVM_ABI Instruction * findNearestCommonDominator(Instruction *I1, Instruction *I2) const
Find the nearest instruction I that dominates both I1 and I2, in the sense that a result produced bef...
static ErrorSuccess success()
Create a success value.
SyncScope::ID getSyncScopeID() const
Returns the synchronization scope ID of this fence instruction.
AtomicOrdering getOrdering() const
Returns the ordering constraint of this fence instruction.
A proxy from a FunctionAnalysisManager to an SCC.
const BasicBlock & getEntryBlock() const
const BasicBlock & front() const
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
void setEntryCount(uint64_t Count, const DenseSet< GlobalValue::GUID > *Imports=nullptr)
Set the entry count for this function.
Argument * getArg(unsigned i) const
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
LLVM_ABI bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
bool hasLocalLinkage() const
Module * getParent()
Get the module that this global value is contained inside of...
@ PrivateLinkage
Like Internal, but omit from symbol table.
@ InternalLinkage
Rename collisions when linking (static functions).
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
LLVM_ABI void setInitializer(Constant *InitVal)
setInitializer - Sets the initializer for this global variable, removing any existing initializer if ...
CondBrInst * CreateCondBr(Value *Cond, BasicBlock *True, BasicBlock *False, MDNode *BranchWeights=nullptr, MDNode *Unpredictable=nullptr)
Create a conditional 'br Cond, TrueDest, FalseDest' instruction.
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)
Value * CreateIsNull(Value *Arg, const Twine &Name="")
Return a boolean value testing if Arg == 0.
LLVM_ABI bool isLifetimeStartOrEnd() const LLVM_READONLY
Return true if the instruction is a llvm.lifetime.start or llvm.lifetime.end marker.
LLVM_ABI bool mayWriteToMemory() const LLVM_READONLY
Return true if this instruction may modify memory.
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
LLVM_ABI bool mayHaveSideEffects() const LLVM_READONLY
Return true if the instruction may have side effects.
LLVM_ABI bool mayReadFromMemory() const LLVM_READONLY
Return true if this instruction may read memory.
iterator_range< user_iterator > users()
void setDebugLoc(DebugLoc Loc)
Set the debug location information for this instruction.
LLVM_ABI void setSuccessor(unsigned Idx, BasicBlock *BB)
Update the specified successor to point at the provided block.
LLVM_ABI std::optional< StringRef > getSyncScopeName(SyncScope::ID Id) const
getSyncScopeName - Returns the name of a SyncScope::ID registered with LLVMContext,...
LLVM_ABI const DiagnosticHandler * getDiagHandlerPtr() const
getDiagHandlerPtr - Returns const raw pointer of DiagnosticHandler set by setDiagnosticHandler.
A node in the call graph.
An SCC of the call graph.
A lazily constructed view of the call graph of a module.
const MDOperand & getOperand(unsigned I) const
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
unsigned getNumOperands() const
Return number of MDNode operands.
LLVM_ABI void eraseFromParent()
This method unlinks 'this' from the containing function and deletes it.
LLVM_ABI StringRef getName() const
Return the name of the corresponding LLVM basic block, or an empty string.
A Module instance is used to store all the information related to an LLVM module.
const Triple & getTargetTriple() const
Get the target triple which is a string describing the target host.
LLVM_ABI Constant * getOrCreateIdent(Constant *SrcLocStr, uint32_t SrcLocStrSize, omp::IdentFlag Flags=omp::IdentFlag(0), unsigned Reserve2Flags=0)
Return an ident_t* encoding the source location SrcLocStr and Flags.
LLVM_ABI FunctionCallee getOrCreateRuntimeFunction(Module &M, omp::RuntimeFunction FnID)
Return the function declaration for the runtime function with FnID.
static LLVM_ABI std::pair< int32_t, int32_t > readThreadBoundsForKernel(const Triple &T, Function &Kernel)
}
LLVM_ABI Constant * getOrCreateSrcLocStr(StringRef LocStr, uint32_t &SrcLocStrSize)
Return the (LLVM-IR) string describing the source location LocStr.
IRBuilder<>::InsertPoint InsertPointTy
Type used throughout for insertion points.
IRBuilder Builder
The LLVM-IR Builder used to create IR.
static LLVM_ABI std::pair< int32_t, int32_t > readTeamBoundsForKernel(const Triple &T, Function &Kernel)
Read/write a bounds on teams for Kernel.
bool updateToLocation(const LocationDescription &Loc)
Update the internal location to Loc.
LLVM_ABI PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG, CGSCCUpdateResult &UR)
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
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 none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
static LLVM_ABI ProfileSummary * getFromMD(Metadata *MD)
Construct profile summary from metdata.
static ReturnInst * Create(LLVMContext &C, Value *retVal=nullptr, InsertPosition InsertBefore=nullptr)
A vector that has set insertion semantics.
size_type size() const
Determine the number of elements in the SetVector.
size_type count(const_arg_type key) const
Count the number of elements of a given key in the SetVector.
bool insert(const value_type &X)
Insert a new element into the SetVector.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
reference emplace_back(ArgTypes &&... Args)
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Triple - Helper class for working with autoconf configuration names.
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
LLVM_ABI unsigned getPointerAddressSpace() const
Get the address space of this pointer or pointer vector type.
static UncondBrInst * Create(BasicBlock *Target, InsertPosition InsertBefore=nullptr)
static LLVM_ABI UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
A Use represents the edge between a Value definition and its users.
LLVM_ABI bool replaceUsesOfWith(Value *From, Value *To)
Replace uses of one Value with another.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void setName(const Twine &Name)
Change the name of the value.
bool hasOneUse() const
Return true if there is exactly one use of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVMContext & getContext() const
All values hold a context through their type.
iterator_range< user_iterator > users()
LLVM_ABI const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
const ParentTy * getParent() const
self_iterator getIterator()
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
GlobalVariable * getKernelEnvironementGVFromKernelInitCB(CallBase *KernelInitCB)
ConstantStruct * getKernelEnvironementFromKernelInitCB(CallBase *KernelInitCB)
Abstract Attribute helper functions.
LLVM_ABI bool isValidAtPosition(const ValueAndContext &VAC, InformationCache &InfoCache)
Return true if the value of VAC is a valid at the position of VAC, that is a constant,...
LLVM_ABI bool isPotentiallyAffectedByBarrier(Attributor &A, const Instruction &I, const AbstractAttribute &QueryingAA)
Return true if I is potentially affected by a barrier.
LLVM_ABI bool isNoSyncInst(Attributor &A, const Instruction &I, const AbstractAttribute &QueryingAA)
Return true if I is a nosync instruction.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
E & operator^=(E &LHS, E RHS)
@ BasicBlock
Various leaf nodes.
@ SingleThread
Synchronized with respect to signal handlers executing in the same thread.
@ System
Synchronized with respect to all concurrently executing threads.
initializer< Ty > init(const Ty &Val)
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
constexpr uint64_t PointerSize
aarch64 pointer size.
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
LLVM_ABI bool isOpenMPDevice(Module &M)
Helper to determine if M is a OpenMP target offloading device module.
LLVM_ABI bool containsOpenMP(Module &M)
Helper to determine if M contains OpenMP.
InternalControlVar
IDs for all Internal Control Variables (ICVs).
RuntimeFunction
IDs for all omp runtime library (RTL) functions.
LLVM_ABI KernelSet getDeviceKernels(Module &M)
Get OpenMP device kernels in M.
@ OMP_TGT_EXEC_MODE_GENERIC_SPMD
@ OMP_TGT_EXEC_MODE_GENERIC
SetVector< Kernel > KernelSet
Set of kernels in the module.
Function * Kernel
Summary of a kernel (=entry point for target offloading).
LLVM_ABI bool isOpenMPKernel(Function &Fn)
Return true iff Fn is an OpenMP GPU kernel; Fn has the "kernel" attribute.
DiagnosticInfoOptimizationBase::Argument NV
NodeAddr< UseNode * > Use
friend class Instruction
Iterator for Instructions in a `BasicBlock.
LLVM_ABI iterator begin() const
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
bool succ_empty(const Instruction *I)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI bool isRemovableAlloc(const CallBase *V, const TargetLibraryInfo *TLI)
Return true if this is a call to an allocation function that does not have side effects that we are r...
bool operator!=(uint64_t V1, const APInt &V2)
constexpr from_range_t from_range
Value * GetPointerBaseWithConstantOffset(Value *Ptr, int64_t &Offset, const DataLayout &DL, bool AllowNonInbounds=true)
Analyze the specified pointer to see if it can be expressed as a base pointer plus a constant offset.
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
AnalysisManager< LazyCallGraph::SCC, LazyCallGraph & > CGSCCAnalysisManager
The CGSCC analysis manager.
@ ThinLTOPostLink
ThinLTO postlink (backend compile) phase.
@ FullLTOPostLink
Full LTO postlink (backend compile) phase.
@ ThinLTOPreLink
ThinLTO prelink (summary) phase.
auto dyn_cast_or_null(const Y &Val)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
std::optional< std::pair< AtomicScope, bool > > parseAtomicScopeIRString(const Triple &T, StringRef Name)
Parses a target syncscope string into its abstract scope, the inverse of getAtomicScopeIRString.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
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...
MutableArrayRef(T &OneElt) -> MutableArrayRef< T >
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
bool operator&=(SparseBitVector< ElementSize > *LHS, const SparseBitVector< ElementSize > &RHS)
LLVM_ABI BasicBlock * SplitBlock(BasicBlock *Old, BasicBlock::iterator SplitPt, DominatorTree *DT, LoopInfo *LI=nullptr, MemorySSAUpdater *MSSAU=nullptr, const Twine &BBName="")
Split the specified block at the specified instruction.
auto count(R &&Range, const E &Element)
Wrapper function around std::count to count the number of times an element Element occurs in the give...
ArrayRef(const T &OneElt) -> ArrayRef< T >
LLVM_ABI Value * getFreedOperand(const CallBase *CB, const TargetLibraryInfo *TLI)
If this if a call to a free function, return the freed operand.
std::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
auto predecessors(const MachineBasicBlock *BB)
LLVM_ABI Constant * ConstantFoldInsertValueInstruction(Constant *Agg, Constant *Val, ArrayRef< unsigned > Idxs)
Attempt to constant fold an insertvalue instruction with the specified operands and indices.
@ OPTIONAL
The target may be valid if the source is not.
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
BumpPtrAllocatorImpl<> BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
@ End
Run the machine verifier once, at the end of the pipeline.
LLVM_ABI void setFittedBranchWeights(Instruction &I, ArrayRef< uint64_t > Weights, bool IsExpected, bool ElideAllZero=false)
Variant of setBranchWeights where the Weights will be fit first to uint32_t by shifting right.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
static LLVM_ABI AAExecutionDomain & createForPosition(const IRPosition &IRP, Attributor &A)
Create an abstract attribute view for the position IRP.
AAExecutionDomain(const IRPosition &IRP, Attributor &A)
static LLVM_ABI const char ID
Unique ID (due to the unique address)
AccessKind
Simple enum to distinguish read/write/read-write accesses.
StateType::base_t MemoryLocationsKind
static LLVM_ABI bool isAlignedBarrier(const CallBase &CB, bool ExecutedAligned)
Helper function to determine if CB is an aligned (GPU) barrier.
Base struct for all "concrete attribute" deductions.
virtual const char * getIdAddr() const =0
This function should return the address of the ID of the AbstractAttribute.
An interface to query the internal state of an abstract attribute.
Wrapper for FunctionAnalysisManager.
Configuration for the Attributor.
std::function< void(Attributor &A, const Function &F)> InitializationCallback
Callback function to be invoked on internal functions marked live.
std::optional< unsigned > MaxFixpointIterations
Maximum number of iterations to run until fixpoint.
bool RewriteSignatures
Flag to determine if we rewrite function signatures.
OptimizationRemarkGetter OREGetter
IPOAmendableCBTy IPOAmendableCB
bool IsModulePass
Is the user of the Attributor a module pass or not.
std::function< bool(Attributor &A, const AbstractAttribute &AA, CallBase &CB, Function &AssumedCallee, unsigned NumAssumedCallees)> IndirectCalleeSpecializationCallback
Callback function to determine if an indirect call targets should be made direct call targets (with a...
bool DefaultInitializeLiveInternals
Flag to determine if we want to initialize all default AAs for an internal function marked live.
The fixpoint analysis framework that orchestrates the attribute deduction.
static LLVM_ABI bool isInternalizable(Function &F)
Returns true if the function F can be internalized.
std::function< std::optional< Value * >( const IRPosition &, const AbstractAttribute *, bool &)> SimplifictionCallbackTy
Register CB as a simplification callback.
std::function< std::optional< Constant * >( const GlobalVariable &, const AbstractAttribute *, bool &)> GlobalVariableSimplifictionCallbackTy
Register CB as a simplification callback.
std::function< bool(Attributor &, const AbstractAttribute *)> VirtualUseCallbackTy
static LLVM_ABI bool internalizeFunctions(SmallPtrSetImpl< Function * > &FnSet, DenseMap< Function *, Function * > &FnMap)
Make copies of each function in the set FnSet such that the copied version has internal linkage after...
Simple wrapper for a single bit (boolean) state.
Support structure for SCC passes to communicate updates the call graph back to the CGSCC pass manager...
bool isAnyRemarkEnabled(StringRef PassName) const
Return true if any type of remarks are enabled for this pass.
Helper to describe and deal with positions in the LLVM-IR.
static const IRPosition callsite_returned(const CallBase &CB)
Create a position describing the returned value of CB.
static const IRPosition returned(const Function &F, const CallBaseContext *CBContext=nullptr)
Create a position describing the returned value of F.
static const IRPosition value(const Value &V, const CallBaseContext *CBContext=nullptr)
Create a position describing the value of V.
static const IRPosition inst(const Instruction &I, const CallBaseContext *CBContext=nullptr)
Create a position describing the instruction I.
@ IRP_ARGUMENT
An attribute for a function argument.
@ IRP_RETURNED
An attribute for the function return value.
@ IRP_CALL_SITE
An attribute for a call site (function scope).
@ IRP_CALL_SITE_RETURNED
An attribute for a call site return value.
@ IRP_FUNCTION
An attribute for a function (scope).
@ IRP_FLOAT
A position that is not associated with a spot suitable for attributes.
@ IRP_CALL_SITE_ARGUMENT
An attribute for a call site argument.
@ IRP_INVALID
An invalid position.
static const IRPosition function(const Function &F, const CallBaseContext *CBContext=nullptr)
Create a position describing the function scope of F.
Kind getPositionKind() const
Return the associated position kind.
static const IRPosition callsite_function(const CallBase &CB)
Create a position describing the function scope of CB.
Defines various target-specific GPU grid values that must be consistent between host RTL (plugin),...