51#include "llvm/IR/IntrinsicsAMDGPU.h"
52#include "llvm/IR/IntrinsicsNVPTX.h"
69#define DEBUG_TYPE "openmp-opt"
72 "openmp-opt-disable",
cl::desc(
"Disable OpenMP specific optimizations."),
76 "openmp-opt-enable-merging",
82 cl::desc(
"Disable function internalization."),
93 "openmp-hide-memory-transfer-latency",
94 cl::desc(
"[WIP] Tries to hide the latency of host to device memory"
99 "openmp-opt-disable-deglobalization",
100 cl::desc(
"Disable OpenMP optimizations involving deglobalization."),
104 "openmp-opt-disable-spmdization",
105 cl::desc(
"Disable OpenMP optimizations involving SPMD-ization."),
109 "openmp-opt-disable-folding",
114 "openmp-opt-disable-state-machine-rewrite",
115 cl::desc(
"Disable OpenMP optimizations that replace the state machine."),
119 "openmp-opt-disable-barrier-elimination",
120 cl::desc(
"Disable OpenMP optimizations that eliminate barriers."),
124 "openmp-opt-print-module-after",
125 cl::desc(
"Print the current module after OpenMP optimizations."),
129 "openmp-opt-print-module-before",
130 cl::desc(
"Print the current module before OpenMP optimizations."),
134 "openmp-opt-inline-device",
145 cl::desc(
"Maximal number of attributor iterations."),
150 cl::desc(
"Maximum amount of shared memory to use."),
151 cl::init(std::numeric_limits<unsigned>::max()));
154 "openmp-opt-max-callees-for-specialization",
cl::Hidden,
155 cl::desc(
"Number of possible callees above which an indirect call site is "
156 "left alone rather than specialized into an if-cascade."),
160 "Number of OpenMP runtime calls deduplicated");
162 "Number of OpenMP parallel regions deleted");
164 "Number of OpenMP runtime functions identified");
166 "Number of OpenMP runtime function uses identified");
168 "Number of OpenMP target region entry points (=kernels) identified");
170 "Number of non-OpenMP target region kernels identified");
172 "Number of OpenMP target region entry points (=kernels) executed in "
173 "SPMD-mode instead of generic-mode");
174STATISTIC(NumOpenMPTargetRegionKernelsWithoutStateMachine,
175 "Number of OpenMP target region entry points (=kernels) executed in "
176 "generic-mode without a state machines");
177STATISTIC(NumOpenMPTargetRegionKernelsCustomStateMachineWithFallback,
178 "Number of OpenMP target region entry points (=kernels) executed in "
179 "generic-mode with customized state machines with fallback");
180STATISTIC(NumOpenMPTargetRegionKernelsCustomStateMachineWithoutFallback,
181 "Number of OpenMP target region entry points (=kernels) executed in "
182 "generic-mode with customized state machines without fallback");
184 NumOpenMPParallelRegionsReplacedInGPUStateMachine,
185 "Number of OpenMP parallel regions replaced with ID in GPU state machines");
187 "Number of OpenMP parallel regions merged");
189 "Amount of memory pushed to shared memory");
190STATISTIC(NumBarriersEliminated,
"Number of redundant barriers eliminated");
218#define KERNEL_ENVIRONMENT_IDX(MEMBER, IDX) \
219 constexpr unsigned MEMBER##Idx = IDX;
224#undef KERNEL_ENVIRONMENT_IDX
226#define KERNEL_ENVIRONMENT_CONFIGURATION_IDX(MEMBER, IDX) \
227 constexpr unsigned MEMBER##Idx = IDX;
237#undef KERNEL_ENVIRONMENT_CONFIGURATION_IDX
239#define KERNEL_ENVIRONMENT_GETTER(MEMBER, RETURNTYPE) \
240 RETURNTYPE *get##MEMBER##FromKernelEnvironment(ConstantStruct *KernelEnvC) { \
241 return cast<RETURNTYPE>(KernelEnvC->getAggregateElement(MEMBER##Idx)); \
247#undef KERNEL_ENVIRONMENT_GETTER
249#define KERNEL_ENVIRONMENT_CONFIGURATION_GETTER(MEMBER) \
250 ConstantInt *get##MEMBER##FromKernelEnvironment( \
251 ConstantStruct *KernelEnvC) { \
252 ConstantStruct *ConfigC = \
253 getConfigurationFromKernelEnvironment(KernelEnvC); \
254 return dyn_cast<ConstantInt>(ConfigC->getAggregateElement(MEMBER##Idx)); \
265#undef KERNEL_ENVIRONMENT_CONFIGURATION_GETTER
269 constexpr int InitKernelEnvironmentArgNo = 0;
284struct AAHeapToShared;
291 OMPInformationCache(
Module &M, AnalysisGetter &AG,
295 OpenMPPostLink(OpenMPPostLink) {
298 const Triple
T(OMPBuilder.M.getTargetTriple());
299 switch (
T.getArch()) {
303 assert(OMPBuilder.Config.IsTargetDevice &&
304 "OpenMP AMDGPU/NVPTX is only prepared to deal with device code.");
305 OMPBuilder.Config.IsGPU =
true;
308 OMPBuilder.Config.IsGPU =
false;
311 OMPBuilder.initialize();
312 initializeRuntimeFunctions(M);
313 initializeInternalControlVars();
317 struct InternalControlVarInfo {
325 StringRef EnvVarName;
331 ConstantInt *InitValue;
344 struct RuntimeFunctionInfo {
365 using UseVector = SmallVector<Use *, 16>;
368 void clearUsesMap() { UsesMap.clear(); }
371 operator bool()
const {
return Declaration; }
374 UseVector &getOrCreateUseVector(
Function *
F) {
375 std::shared_ptr<UseVector> &UV = UsesMap[
F];
377 UV = std::make_shared<UseVector>();
383 const UseVector *getUseVector(
Function &
F)
const {
384 auto I = UsesMap.find(&
F);
385 if (
I != UsesMap.end())
386 return I->second.get();
391 size_t getNumFunctionsWithUses()
const {
return UsesMap.size(); }
395 size_t getNumArgs()
const {
return ArgumentTypes.size(); }
400 void foreachUse(SmallVectorImpl<Function *> &SCC,
401 function_ref<
bool(Use &,
Function &)> CB) {
409 SmallVector<unsigned, 8> ToBeDeleted;
413 UseVector &UV = getOrCreateUseVector(
F);
423 while (!ToBeDeleted.
empty()) {
433 DenseMap<Function *, std::shared_ptr<UseVector>> UsesMap;
437 decltype(UsesMap)::iterator
begin() {
return UsesMap.begin(); }
438 decltype(UsesMap)::iterator
end() {
return UsesMap.end(); }
442 OpenMPIRBuilder OMPBuilder;
446 RuntimeFunction::OMPRTL___last>
450 DenseMap<Function *, RuntimeFunction> RuntimeFunctionIDMap;
454 InternalControlVar::ICV___last>
459 void initializeInternalControlVars() {
460#define ICV_RT_SET(_Name, RTL) \
462 auto &ICV = ICVs[_Name]; \
465#define ICV_RT_GET(Name, RTL) \
467 auto &ICV = ICVs[Name]; \
470#define ICV_DATA_ENV(Enum, _Name, _EnvVarName, Init) \
472 auto &ICV = ICVs[Enum]; \
475 ICV.InitKind = Init; \
476 ICV.EnvVarName = _EnvVarName; \
477 switch (ICV.InitKind) { \
478 case ICV_IMPLEMENTATION_DEFINED: \
479 ICV.InitValue = nullptr; \
482 ICV.InitValue = ConstantInt::get( \
483 Type::getInt32Ty(OMPBuilder.Int32->getContext()), 0); \
486 ICV.InitValue = ConstantInt::getFalse(OMPBuilder.Int1->getContext()); \
492#include "llvm/Frontend/OpenMP/OMPKinds.def"
498 static bool declMatchesRTFTypes(
Function *
F,
Type *RTFRetType,
505 if (
F->getReturnType() != RTFRetType)
507 if (
F->arg_size() != RTFArgTypes.
size())
510 auto *RTFTyIt = RTFArgTypes.
begin();
511 for (Argument &Arg :
F->args()) {
512 if (Arg.getType() != *RTFTyIt)
522 unsigned collectUses(RuntimeFunctionInfo &RFI,
bool CollectStats =
true) {
523 unsigned NumUses = 0;
524 if (!RFI.Declaration)
526 OMPBuilder.addAttributes(RFI.Kind, *RFI.Declaration);
529 NumOpenMPRuntimeFunctionsIdentified += 1;
530 NumOpenMPRuntimeFunctionUsesIdentified += RFI.Declaration->getNumUses();
534 for (Use &U : RFI.Declaration->uses()) {
536 if (!
CGSCC ||
CGSCC->empty() ||
CGSCC->contains(UserI->getFunction())) {
537 RFI.getOrCreateUseVector(UserI->getFunction()).push_back(&U);
541 RFI.getOrCreateUseVector(
nullptr).push_back(&U);
550 auto &RFI = RFIs[RTF];
552 collectUses(RFI,
false);
560 void setCallbackMetadata(
Function *
F,
unsigned ArgNo, ArrayRef<int> Indices,
562 if (!
F ||
F->hasMetadata(LLVMContext::MD_callback))
565 LLVMContext &Ctx =
F->getContext();
567 F->addMetadata(LLVMContext::MD_callback,
568 *
MDNode::get(Ctx, {MDB.createCallbackEncoding(ArgNo, Indices,
576 static Function *getAnalyzableCallback(
const CallBase &CB) {
580 MDNode *CallbackMD =
Callee->getMetadata(LLVMContext::MD_callback);
586 if (!Encoding || Encoding->getNumOperands() == 0)
597 if (!Callback ||
Callback->isDeclaration())
603 void recollectUses() {
604 for (
int Idx = 0; Idx < RFIs.size(); ++Idx)
609 void setCallingConvention(FunctionCallee Callee, CallInst *CI) {
624 RuntimeFunctionInfo &RFI = RFIs[Fn];
626 if (!RFI.Declaration || RFI.Declaration->isDeclaration())
634 void initializeRuntimeFunctions(
Module &M) {
637#define OMP_TYPE(VarName, ...) \
638 Type *VarName = OMPBuilder.VarName; \
641#define OMP_ARRAY_TYPE(VarName, ...) \
642 ArrayType *VarName##Ty = OMPBuilder.VarName##Ty; \
644 PointerType *VarName##PtrTy = OMPBuilder.VarName##PtrTy; \
645 (void)VarName##PtrTy;
647#define OMP_FUNCTION_TYPE(VarName, ...) \
648 FunctionType *VarName = OMPBuilder.VarName; \
650 PointerType *VarName##Ptr = OMPBuilder.VarName##Ptr; \
653#define OMP_STRUCT_TYPE(VarName, ...) \
654 StructType *VarName = OMPBuilder.VarName; \
656 PointerType *VarName##Ptr = OMPBuilder.VarName##Ptr; \
659#define OMP_RTL(_Enum, _Name, _IsVarArg, _ReturnType, ...) \
661 SmallVector<Type *, 8> ArgsTypes({__VA_ARGS__}); \
662 Function *F = M.getFunction(_Name); \
663 RTLFunctions.insert(F); \
664 if (declMatchesRTFTypes(F, OMPBuilder._ReturnType, ArgsTypes)) { \
665 RuntimeFunctionIDMap[F] = _Enum; \
666 auto &RFI = RFIs[_Enum]; \
669 RFI.IsVarArg = _IsVarArg; \
670 RFI.ReturnType = OMPBuilder._ReturnType; \
671 RFI.ArgumentTypes = std::move(ArgsTypes); \
672 RFI.Declaration = F; \
673 unsigned NumUses = collectUses(RFI); \
676 dbgs() << TAG << RFI.Name << (RFI.Declaration ? "" : " not") \
678 if (RFI.Declaration) \
679 dbgs() << TAG << "-> got " << NumUses << " uses in " \
680 << RFI.getNumFunctionsWithUses() \
681 << " different functions.\n"; \
686#define OMP_RTL_CB_INFO(_Enum, _Name, _ArgNo, _ArgIndices, _IsVarArg) \
687 setCallbackMetadata(M.getFunction(_Name), _ArgNo, _ArgIndices, _IsVarArg);
689#include "llvm/Frontend/OpenMP/OMPKinds.def"
695 for (StringRef Prefix : {
"__kmpc",
"_ZN4ompx",
"omp_"})
696 if (
F.hasFnAttribute(Attribute::NoInline) &&
697 F.getName().starts_with(Prefix) &&
698 !
F.hasFnAttribute(Attribute::OptimizeNone))
699 F.removeFnAttr(Attribute::NoInline);
707 DenseSet<const Function *> RTLFunctions;
710 bool OpenMPPostLink =
false;
717 SmallPtrSet<Function *, 8> SPMDizedKernels;
720template <
typename Ty,
bool InsertInval
idates = true>
722 bool contains(
const Ty &Elem)
const {
return Set.contains(Elem); }
723 bool insert(
const Ty &Elem) {
724 if (InsertInvalidates)
725 BooleanState::indicatePessimisticFixpoint();
726 return Set.insert(Elem);
729 const Ty &operator[](
int Idx)
const {
return Set[Idx]; }
730 bool operator==(
const BooleanStateWithSetVector &
RHS)
const {
731 return BooleanState::operator==(
RHS) && Set ==
RHS.Set;
733 bool operator!=(
const BooleanStateWithSetVector &
RHS)
const {
734 return !(*
this ==
RHS);
737 bool empty()
const {
return Set.empty(); }
738 size_t size()
const {
return Set.size(); }
741 BooleanStateWithSetVector &
operator^=(
const BooleanStateWithSetVector &
RHS) {
742 BooleanState::operator^=(
RHS);
743 Set.insert_range(
RHS.Set);
752 typename decltype(Set)::iterator
begin() {
return Set.begin(); }
753 typename decltype(Set)::iterator
end() {
return Set.end(); }
754 typename decltype(Set)::const_iterator
begin()
const {
return Set.begin(); }
755 typename decltype(Set)::const_iterator
end()
const {
return Set.end(); }
758template <
typename Ty,
bool InsertInval
idates = true>
759using BooleanStateWithPtrSetVector =
760 BooleanStateWithSetVector<Ty *, InsertInvalidates>;
764 bool IsAtFixpoint =
false;
768 BooleanStateWithPtrSetVector<CallBase,
false>
769 ReachedKnownParallelRegions;
772 BooleanStateWithPtrSetVector<CallBase> ReachedUnknownParallelRegions;
777 BooleanStateWithPtrSetVector<Instruction, false> SPMDCompatibilityTracker;
781 CallBase *KernelInitCB =
nullptr;
785 ConstantStruct *KernelEnvC =
nullptr;
789 CallBase *KernelDeinitCB =
nullptr;
792 bool IsKernelEntry =
false;
795 BooleanStateWithPtrSetVector<Function, false> ReachingKernelEntries;
800 BooleanStateWithSetVector<uint8_t> ParallelLevels;
803 bool NestedParallelism =
false;
808 KernelInfoState() =
default;
809 KernelInfoState(
bool BestState) {
811 indicatePessimisticFixpoint();
815 bool isValidState()
const override {
return true; }
818 bool isAtFixpoint()
const override {
return IsAtFixpoint; }
823 ParallelLevels.indicatePessimisticFixpoint();
824 ReachingKernelEntries.indicatePessimisticFixpoint();
825 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
826 ReachedKnownParallelRegions.indicatePessimisticFixpoint();
827 ReachedUnknownParallelRegions.indicatePessimisticFixpoint();
828 NestedParallelism =
true;
829 return ChangeStatus::CHANGED;
835 ParallelLevels.indicateOptimisticFixpoint();
836 ReachingKernelEntries.indicateOptimisticFixpoint();
837 SPMDCompatibilityTracker.indicateOptimisticFixpoint();
838 ReachedKnownParallelRegions.indicateOptimisticFixpoint();
839 ReachedUnknownParallelRegions.indicateOptimisticFixpoint();
840 return ChangeStatus::UNCHANGED;
844 KernelInfoState &getAssumed() {
return *
this; }
845 const KernelInfoState &getAssumed()
const {
return *
this; }
848 if (SPMDCompatibilityTracker !=
RHS.SPMDCompatibilityTracker)
850 if (ReachedKnownParallelRegions !=
RHS.ReachedKnownParallelRegions)
852 if (ReachedUnknownParallelRegions !=
RHS.ReachedUnknownParallelRegions)
854 if (ReachingKernelEntries !=
RHS.ReachingKernelEntries)
856 if (ParallelLevels !=
RHS.ParallelLevels)
858 if (NestedParallelism !=
RHS.NestedParallelism)
864 bool mayContainParallelRegion() {
865 return !ReachedKnownParallelRegions.empty() ||
866 !ReachedUnknownParallelRegions.empty();
870 static KernelInfoState getBestState() {
return KernelInfoState(
true); }
872 static KernelInfoState getBestState(KernelInfoState &KIS) {
873 return getBestState();
877 static KernelInfoState getWorstState() {
return KernelInfoState(
false); }
880 KernelInfoState
operator^=(
const KernelInfoState &KIS) {
882 if (KIS.KernelInitCB) {
883 if (KernelInitCB && KernelInitCB != KIS.KernelInitCB)
886 KernelInitCB = KIS.KernelInitCB;
888 if (KIS.KernelDeinitCB) {
889 if (KernelDeinitCB && KernelDeinitCB != KIS.KernelDeinitCB)
892 KernelDeinitCB = KIS.KernelDeinitCB;
894 if (KIS.KernelEnvC) {
895 if (KernelEnvC && KernelEnvC != KIS.KernelEnvC)
898 KernelEnvC = KIS.KernelEnvC;
900 SPMDCompatibilityTracker ^= KIS.SPMDCompatibilityTracker;
901 ReachedKnownParallelRegions ^= KIS.ReachedKnownParallelRegions;
902 ReachedUnknownParallelRegions ^= KIS.ReachedUnknownParallelRegions;
903 NestedParallelism |= KIS.NestedParallelism;
907 KernelInfoState
operator&=(
const KernelInfoState &KIS) {
908 return (*
this ^= KIS);
918 AllocaInst *Array =
nullptr;
920 SmallVector<Value *, 8> StoredValues;
922 SmallVector<StoreInst *, 8> LastAccesses;
924 OffloadArray() =
default;
930 bool initialize(AllocaInst &Array, Instruction &Before) {
931 if (!getValues(Array, Before))
934 this->Array = &Array;
938 static const unsigned DeviceIDArgNum = 1;
939 static const unsigned BasePtrsArgNum = 3;
940 static const unsigned PtrsArgNum = 4;
941 static const unsigned SizesArgNum = 5;
947 bool getValues(AllocaInst &Array, Instruction &Before) {
949 const DataLayout &
DL = Array.getDataLayout();
950 std::optional<TypeSize> ArraySize = Array.getAllocationSize(
DL);
951 if (!ArraySize || !ArraySize->isFixed())
955 StoredValues.assign(NumValues,
nullptr);
956 LastAccesses.assign(NumValues,
nullptr);
964 for (Instruction &
I : *BB) {
980 LastAccesses[Idx] = S;
991 const unsigned NumValues = StoredValues.size();
992 for (
unsigned I = 0;
I < NumValues; ++
I) {
993 if (!StoredValues[
I] || !LastAccesses[
I])
1003 using OptimizationRemarkGetter =
1004 function_ref<OptimizationRemarkEmitter &(
Function *)>;
1006 OpenMPOpt(SmallVectorImpl<Function *> &SCC, CallGraphUpdater &CGUpdater,
1007 OptimizationRemarkGetter OREGetter,
1008 OMPInformationCache &OMPInfoCache, Attributor &A)
1009 : M(*(*SCC.
begin())->
getParent()), SCC(SCC), CGUpdater(CGUpdater),
1010 OREGetter(OREGetter), OMPInfoCache(OMPInfoCache), A(A) {}
1013 bool remarksEnabled() {
1014 auto &Ctx = M.getContext();
1019 bool run(
bool IsModulePass) {
1029 Changed |= runAttributor(IsModulePass);
1032 OMPInfoCache.recollectUses();
1035 Changed |= rewriteDeviceCodeStateMachine();
1041 Changed |= removeSPMDParallelWrappers();
1043 if (remarksEnabled())
1044 analysisGlobalization();
1051 Changed |= runAttributor(IsModulePass);
1054 OMPInfoCache.recollectUses();
1056 Changed |= deleteParallelRegions();
1059 Changed |= hideMemTransfersLatency();
1060 Changed |= deduplicateRuntimeCalls();
1062 if (mergeParallelRegions()) {
1063 deduplicateRuntimeCalls();
1069 if (OMPInfoCache.OpenMPPostLink)
1070 Changed |= removeRuntimeSymbols();
1077 void printICVs()
const {
1082 for (
auto ICV : ICVs) {
1083 auto ICVInfo = OMPInfoCache.ICVs[ICV];
1084 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
1085 return ORA <<
"OpenMP ICV " <<
ore::NV(
"OpenMPICV", ICVInfo.Name)
1087 << (ICVInfo.InitValue
1088 ?
toString(ICVInfo.InitValue->getValue(), 10,
true)
1089 :
"IMPLEMENTATION_DEFINED");
1098 void printKernels()
const {
1103 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
1104 return ORA <<
"OpenMP GPU kernel "
1105 <<
ore::NV(
"OpenMPGPUKernel",
F->getName()) <<
"\n";
1114 static CallInst *getCallIfRegularCall(
1115 Use &U, OMPInformationCache::RuntimeFunctionInfo *RFI =
nullptr) {
1126 static CallInst *getCallIfRegularCall(
1127 Value &V, OMPInformationCache::RuntimeFunctionInfo *RFI =
nullptr) {
1138 bool mergeParallelRegions() {
1139 const unsigned CallbackCalleeOperand = 2;
1140 const unsigned CallbackFirstArgOperand = 3;
1144 OMPInformationCache::RuntimeFunctionInfo &RFI =
1145 OMPInfoCache.RFIs[OMPRTL___kmpc_fork_call];
1147 if (!RFI.Declaration)
1151 OMPInformationCache::RuntimeFunctionInfo UnmergableCallsInfo[] = {
1152 OMPInfoCache.RFIs[OMPRTL___kmpc_push_proc_bind],
1153 OMPInfoCache.RFIs[OMPRTL___kmpc_push_num_threads],
1157 LoopInfo *LI =
nullptr;
1158 DominatorTree *DT =
nullptr;
1160 SmallDenseMap<BasicBlock *, SmallPtrSet<Instruction *, 4>> BB2PRMap;
1162 BasicBlock *StartBB =
nullptr, *EndBB =
nullptr;
1163 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
1165 BasicBlock *CGStartBB = CodeGenIP.getBlock();
1167 SplitBlock(CGStartBB, &*CodeGenIP.getPoint(), DT, LI);
1168 assert(StartBB !=
nullptr &&
"StartBB should not be null");
1170 assert(EndBB !=
nullptr &&
"EndBB should not be null");
1171 EndBB->getTerminator()->setSuccessor(0, CGEndBB);
1175 auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
Value &,
1176 Value &Inner,
Value *&ReplacementValue) -> InsertPointTy {
1177 ReplacementValue = &Inner;
1181 auto FiniCB = [&](InsertPointTy CodeGenIP) {
return Error::success(); };
1185 auto CreateSequentialRegion = [&](
Function *OuterFn,
1191 BasicBlock *ParentBB = SeqStartI->getParent();
1193 SplitBlock(ParentBB, SeqEndI->getNextNode(), DT, LI);
1197 SplitBlock(ParentBB, SeqStartI, DT, LI,
nullptr,
"seq.par.merged");
1200 "Expected a different CFG");
1204 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
1206 BasicBlock *CGStartBB = CodeGenIP.getBlock();
1208 SplitBlock(CGStartBB, &*CodeGenIP.getPoint(), DT, LI);
1209 assert(SeqStartBB !=
nullptr &&
"SeqStartBB should not be null");
1211 assert(SeqEndBB !=
nullptr &&
"SeqEndBB should not be null");
1215 auto FiniCB = [&](InsertPointTy CodeGenIP) {
return Error::success(); };
1219 for (Instruction &
I : *SeqStartBB) {
1220 SmallPtrSet<Instruction *, 4> OutsideUsers;
1221 for (User *Usr :
I.users()) {
1229 OutsideUsers.
insert(&UsrI);
1232 if (OutsideUsers.
empty())
1237 const DataLayout &
DL = M.getDataLayout();
1238 AllocaInst *AllocaI =
new AllocaInst(
1239 I.getType(),
DL.getAllocaAddrSpace(),
nullptr,
1244 new StoreInst(&
I, AllocaI, SeqStartBB->getTerminator()->getIterator());
1248 for (Instruction *UsrI : OutsideUsers) {
1249 LoadInst *LoadI =
new LoadInst(
I.getType(), AllocaI,
1250 I.getName() +
".seq.output.load",
1256 OpenMPIRBuilder::LocationDescription Loc(
1257 InsertPointTy(ParentBB, ParentBB->
end()),
DL);
1259 OMPInfoCache.OMPBuilder.createMaster(Loc, BodyGenCB, FiniCB));
1260 cantFail(OMPInfoCache.OMPBuilder.createBarrier({SeqAfterIP, DL},
1276 auto Merge = [&](
const SmallVectorImpl<CallInst *> &MergableCIs,
1280 assert(MergableCIs.
size() > 1 &&
"Assumed multiple mergable CIs");
1282 auto Remark = [&](OptimizationRemark
OR) {
1283 OR <<
"Parallel region merged with parallel region"
1284 << (MergableCIs.
size() > 2 ?
"s" :
"") <<
" at ";
1287 if (CI != MergableCIs.
back())
1295 Function *OriginalFn = BB->getParent();
1297 <<
" parallel regions in " << OriginalFn->
getName()
1301 EndBB =
SplitBlock(BB, MergableCIs.
back()->getNextNode(), DT, LI);
1303 SplitBlock(EndBB, &*EndBB->getFirstInsertionPt(), DT, LI);
1307 assert(BB->getUniqueSuccessor() == StartBB &&
"Expected a different CFG");
1308 const DebugLoc DL = BB->getTerminator()->getDebugLoc();
1313 for (
auto *It = MergableCIs.
begin(), *End = MergableCIs.
end() - 1;
1322 CreateSequentialRegion(OriginalFn, BB, ForkCI->
getNextNode(),
1326 OpenMPIRBuilder::LocationDescription Loc(InsertPointTy(BB, BB->end()),
1328 IRBuilder<>::InsertPoint AllocaIP(
1334 cantFail(OMPInfoCache.OMPBuilder.createParallel(
1335 Loc, AllocaIP, {}, BodyGenCB, PrivCB, FiniCB,
1336 nullptr,
nullptr, OMP_PROC_BIND_default,
1341 OMPInfoCache.OMPBuilder.finalize(OriginalFn);
1347 SmallVector<Value *, 8>
Args;
1348 for (
auto *CI : MergableCIs) {
1350 FunctionType *FT = OMPInfoCache.OMPBuilder.ParallelTask;
1354 for (
unsigned U = CallbackFirstArgOperand,
E = CI->
arg_size(); U <
E;
1364 for (
unsigned U = CallbackFirstArgOperand,
E = CI->
arg_size(); U <
E;
1368 U - (CallbackFirstArgOperand - CallbackCalleeOperand), A);
1371 if (CI != MergableCIs.back()) {
1374 cantFail(OMPInfoCache.OMPBuilder.createBarrier(
1375 {InsertPointTy(NewCI->getParent(),
1376 NewCI->getNextNode()->getIterator()),
1377 NewCI->getDebugLoc()},
1384 assert(OutlinedFn != OriginalFn &&
"Outlining failed");
1385 CGUpdater.registerOutlinedFunction(*OriginalFn, *OutlinedFn);
1386 CGUpdater.reanalyzeFunction(*OriginalFn);
1388 NumOpenMPParallelRegionsMerged += MergableCIs.size();
1396 CallInst *CI = getCallIfRegularCall(U, &RFI);
1403 RFI.foreachUse(SCC, DetectPRsCB);
1409 for (
auto &It : BB2PRMap) {
1410 auto &CIs = It.getSecond();
1425 auto IsMergable = [&](
Instruction &
I,
bool IsBeforeMergableRegion) {
1428 if (
I.isTerminator())
1435 if (IsBeforeMergableRegion) {
1437 if (!CalledFunction)
1444 for (
const auto &RFI : UnmergableCallsInfo) {
1445 if (CalledFunction == RFI.Declaration)
1460 for (
auto It = BB->
begin(), End = BB->
end(); It != End;) {
1464 if (CIs.count(&
I)) {
1470 if (IsMergable(
I, MergableCIs.
empty()))
1475 for (; It != End; ++It) {
1477 if (CIs.count(&SkipI)) {
1479 <<
" due to " <<
I <<
"\n");
1486 if (MergableCIs.
size() > 1) {
1487 MergableCIsVector.
push_back(MergableCIs);
1489 <<
" parallel regions in block " << BB->
getName()
1494 MergableCIs.
clear();
1497 if (!MergableCIsVector.
empty()) {
1500 for (
auto &MergableCIs : MergableCIsVector)
1501 Merge(MergableCIs, BB);
1502 MergableCIsVector.clear();
1509 OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_fork_call);
1510 OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_barrier);
1511 OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_master);
1512 OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_end_master);
1519 bool deleteParallelRegions() {
1520 const unsigned CallbackCalleeOperand = 2;
1522 OMPInformationCache::RuntimeFunctionInfo &RFI =
1523 OMPInfoCache.RFIs[OMPRTL___kmpc_fork_call];
1525 if (!RFI.Declaration)
1530 CallInst *CI = getCallIfRegularCall(U);
1537 if (!Fn->onlyReadsMemory())
1539 if (!Fn->hasFnAttribute(Attribute::WillReturn))
1545 auto Remark = [&](OptimizationRemark
OR) {
1546 return OR <<
"Removing parallel region with no side-effects.";
1552 ++NumOpenMPParallelRegionsDeleted;
1556 RFI.foreachUse(SCC, DeleteCallCB);
1562 bool deduplicateRuntimeCalls() {
1566 OMPRTL_omp_get_num_threads,
1567 OMPRTL_omp_in_parallel,
1568 OMPRTL_omp_get_cancellation,
1569 OMPRTL_omp_get_supported_active_levels,
1570 OMPRTL_omp_get_level,
1571 OMPRTL_omp_get_ancestor_thread_num,
1572 OMPRTL_omp_get_team_size,
1573 OMPRTL_omp_get_active_level,
1574 OMPRTL_omp_in_final,
1575 OMPRTL_omp_get_proc_bind,
1576 OMPRTL_omp_get_num_places,
1577 OMPRTL_omp_get_num_procs,
1578 OMPRTL_omp_get_place_num,
1579 OMPRTL_omp_get_partition_num_places,
1580 OMPRTL_omp_get_partition_place_nums};
1583 SmallSetVector<Value *, 16> GTIdArgs;
1584 collectGlobalThreadIdArguments(GTIdArgs);
1586 <<
" global thread ID arguments\n");
1589 for (
auto DeduplicableRuntimeCallID : DeduplicableRuntimeCallIDs)
1590 Changed |= deduplicateRuntimeCalls(
1591 *
F, OMPInfoCache.RFIs[DeduplicableRuntimeCallID]);
1595 Value *GTIdArg =
nullptr;
1596 for (Argument &Arg :
F->args())
1597 if (GTIdArgs.
count(&Arg)) {
1601 Changed |= deduplicateRuntimeCalls(
1602 *
F, OMPInfoCache.RFIs[OMPRTL___kmpc_global_thread_num], GTIdArg);
1609 bool removeRuntimeSymbols() {
1614 if (GlobalVariable *GV = M.getNamedGlobal(
"__llvm_rpc_client")) {
1615 if (GV->hasNUsesOrMore(1))
1619 GV->eraseFromParent();
1631 bool hideMemTransfersLatency() {
1632 auto &RFI = OMPInfoCache.RFIs[OMPRTL___tgt_target_data_begin_mapper];
1635 auto *RTCall = getCallIfRegularCall(U, &RFI);
1639 OffloadArray OffloadArrays[3];
1640 if (!getValuesInOffloadArrays(*RTCall, OffloadArrays))
1643 LLVM_DEBUG(dumpValuesInOffloadArrays(OffloadArrays));
1646 bool WasSplit =
false;
1647 Instruction *WaitMovementPoint = canBeMovedDownwards(*RTCall);
1648 if (WaitMovementPoint)
1649 WasSplit = splitTargetDataBeginRTC(*RTCall, *WaitMovementPoint);
1654 if (OMPInfoCache.runtimeFnsAvailable(
1655 {OMPRTL___tgt_target_data_begin_mapper_issue,
1656 OMPRTL___tgt_target_data_begin_mapper_wait}))
1657 RFI.foreachUse(SCC, SplitMemTransfers);
1662 void analysisGlobalization() {
1663 auto &RFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
1665 auto CheckGlobalization = [&](
Use &
U,
Function &Decl) {
1666 if (CallInst *CI = getCallIfRegularCall(U, &RFI)) {
1667 auto Remark = [&](OptimizationRemarkMissed ORM) {
1669 <<
"Found thread data sharing on the GPU. "
1670 <<
"Expect degraded performance due to data globalization.";
1678 RFI.foreachUse(SCC, CheckGlobalization);
1683 bool getValuesInOffloadArrays(CallInst &RuntimeCall,
1685 assert(OAs.
size() == 3 &&
"Need space for three offload arrays!");
1695 Value *BasePtrsArg =
1707 if (!OAs[0].
initialize(*BasePtrsArray, RuntimeCall))
1715 if (!OAs[1].
initialize(*PtrsArray, RuntimeCall))
1727 if (!OAs[2].
initialize(*SizesArray, RuntimeCall))
1738 assert(OAs.
size() == 3 &&
"There are three offload arrays to debug!");
1741 std::string ValuesStr;
1742 raw_string_ostream
Printer(ValuesStr);
1743 std::string Separator =
" --- ";
1745 for (
auto *BP : OAs[0].StoredValues) {
1749 LLVM_DEBUG(
dbgs() <<
"\t\toffload_baseptrs: " << ValuesStr <<
"\n");
1752 for (
auto *
P : OAs[1].StoredValues) {
1759 for (
auto *S : OAs[2].StoredValues) {
1763 LLVM_DEBUG(
dbgs() <<
"\t\toffload_sizes: " << ValuesStr <<
"\n");
1768 Instruction *canBeMovedDownwards(CallInst &RuntimeCall) {
1773 bool IsWorthIt =
false;
1792 return RuntimeCall.
getParent()->getTerminator();
1796 bool splitTargetDataBeginRTC(CallInst &RuntimeCall,
1797 Instruction &WaitMovementPoint) {
1801 auto &
IRBuilder = OMPInfoCache.OMPBuilder;
1804 IRBuilder.Builder.SetInsertPoint(&Entry,
1805 Entry.getFirstNonPHIOrDbgOrAlloca());
1807 IRBuilder.AsyncInfo,
nullptr,
"handle");
1814 FunctionCallee IssueDecl =
IRBuilder.getOrCreateRuntimeFunction(
1815 M, OMPRTL___tgt_target_data_begin_mapper_issue);
1818 SmallVector<Value *, 16>
Args;
1819 for (
auto &Arg : RuntimeCall.
args())
1820 Args.push_back(Arg.get());
1821 Args.push_back(Handle);
1825 OMPInfoCache.setCallingConvention(IssueDecl, IssueCallsite);
1830 FunctionCallee WaitDecl =
IRBuilder.getOrCreateRuntimeFunction(
1831 M, OMPRTL___tgt_target_data_begin_mapper_wait);
1833 Value *WaitParams[2] = {
1835 OffloadArray::DeviceIDArgNum),
1839 WaitDecl, WaitParams,
"", WaitMovementPoint.
getIterator());
1840 OMPInfoCache.setCallingConvention(WaitDecl, WaitCallsite);
1845 static Value *combinedIdentStruct(
Value *CurrentIdent,
Value *NextIdent,
1846 bool GlobalOnly,
bool &SingleChoice) {
1847 if (CurrentIdent == NextIdent)
1848 return CurrentIdent;
1853 SingleChoice = !CurrentIdent;
1865 getCombinedIdentFromCallUsesIn(OMPInformationCache::RuntimeFunctionInfo &RFI,
1867 bool SingleChoice =
true;
1868 Value *Ident =
nullptr;
1870 CallInst *CI = getCallIfRegularCall(U, &RFI);
1871 if (!CI || &
F != &Caller)
1874 true, SingleChoice);
1877 RFI.foreachUse(SCC, CombineIdentStruct);
1879 if (!Ident || !SingleChoice) {
1883 if (!OMPInfoCache.OMPBuilder.getInsertionPoint().getBlock())
1884 OMPInfoCache.OMPBuilder.updateToLocation(
1886 F.getEntryBlock().begin()),
1890 uint32_t SrcLocStrSize;
1892 OMPInfoCache.OMPBuilder.getOrCreateDefaultSrcLocStr(SrcLocStrSize);
1893 Ident = OMPInfoCache.OMPBuilder.getOrCreateIdent(Loc, SrcLocStrSize);
1900 bool deduplicateRuntimeCalls(
Function &
F,
1901 OMPInformationCache::RuntimeFunctionInfo &RFI,
1902 Value *ReplVal =
nullptr) {
1903 auto *UV = RFI.getUseVector(
F);
1904 if (!UV || UV->size() + (ReplVal !=
nullptr) < 2)
1908 dbgs() <<
TAG <<
"Deduplicate " << UV->size() <<
" uses of " << RFI.Name
1909 << (ReplVal ?
" with an existing value\n" :
"\n") <<
"\n");
1913 "Unexpected replacement value!");
1916 auto CanBeMoved = [
this](CallBase &CB) {
1922 for (
unsigned U = 1;
U < NumArgs; ++
U)
1930 OMPInfoCache.getAnalysisResultForFunction<DominatorTreeAnalysis>(
F);
1934 for (Use *U : *UV) {
1935 if (CallInst *CI = getCallIfRegularCall(*U, &RFI)) {
1940 if (!CanBeMoved(*CI))
1948 assert(IP &&
"Expected insertion point!");
1958 Value *Ident = getCombinedIdentFromCallUsesIn(RFI,
F,
1966 CallInst *CI = getCallIfRegularCall(U, &RFI);
1967 if (!CI || CI == ReplVal || &
F != &Caller)
1971 auto Remark = [&](OptimizationRemark
OR) {
1972 return OR <<
"OpenMP runtime call "
1973 <<
ore::NV(
"OpenMPOptRuntime", RFI.Name) <<
" deduplicated.";
1982 ++NumOpenMPRuntimeCallsDeduplicated;
1986 RFI.foreachUse(SCC, ReplaceAndDeleteCB);
1992 void collectGlobalThreadIdArguments(SmallSetVector<Value *, 16> >IdArgs) {
1999 auto CallArgOpIsGTId = [&](
Function &
F,
unsigned ArgNo, CallInst &RefCI) {
2000 if (!
F.hasLocalLinkage())
2002 for (Use &U :
F.uses()) {
2003 if (CallInst *CI = getCallIfRegularCall(U)) {
2005 if (CI == &RefCI || GTIdArgs.
count(ArgOp) ||
2006 getCallIfRegularCall(
2007 *ArgOp, &OMPInfoCache.RFIs[OMPRTL___kmpc_global_thread_num]))
2016 auto AddUserArgs = [&](
Value >Id) {
2017 for (Use &U : GTId.uses())
2021 if (CallArgOpIsGTId(*Callee,
U.getOperandNo(), *CI))
2026 OMPInformationCache::RuntimeFunctionInfo &GlobThreadNumRFI =
2027 OMPInfoCache.RFIs[OMPRTL___kmpc_global_thread_num];
2029 GlobThreadNumRFI.foreachUse(SCC, [&](Use &U,
Function &
F) {
2030 if (CallInst *CI = getCallIfRegularCall(U, &GlobThreadNumRFI))
2038 for (
unsigned U = 0;
U < GTIdArgs.
size(); ++
U)
2039 AddUserArgs(*GTIdArgs[U]);
2047 DenseMap<Function *, std::optional<Kernel>> UniqueKernelMap;
2053 Kernel getUniqueKernelFor(Instruction &
I) {
2054 return getUniqueKernelFor(*
I.getFunction());
2059 bool rewriteDeviceCodeStateMachine();
2064 bool removeSPMDParallelWrappers();
2080 template <
typename RemarkKind,
typename RemarkCallBack>
2081 void emitRemark(Instruction *
I, StringRef RemarkName,
2082 RemarkCallBack &&RemarkCB)
const {
2084 auto &ORE = OREGetter(
F);
2088 return RemarkCB(RemarkKind(
DEBUG_TYPE, RemarkName,
I))
2089 <<
" [" << RemarkName <<
"]";
2093 [&]() {
return RemarkCB(RemarkKind(
DEBUG_TYPE, RemarkName,
I)); });
2097 template <
typename RemarkKind,
typename RemarkCallBack>
2099 RemarkCallBack &&RemarkCB)
const {
2100 auto &ORE = OREGetter(
F);
2104 return RemarkCB(RemarkKind(
DEBUG_TYPE, RemarkName,
F))
2105 <<
" [" << RemarkName <<
"]";
2109 [&]() {
return RemarkCB(RemarkKind(
DEBUG_TYPE, RemarkName,
F)); });
2116 SmallVectorImpl<Function *> &SCC;
2120 CallGraphUpdater &CGUpdater;
2123 OptimizationRemarkGetter OREGetter;
2126 OMPInformationCache &OMPInfoCache;
2132 bool runAttributor(
bool IsModulePass) {
2136 registerAAs(IsModulePass);
2141 <<
" functions, result: " <<
Changed <<
".\n");
2143 if (
Changed == ChangeStatus::CHANGED)
2144 OMPInfoCache.invalidateAnalyses();
2146 return Changed == ChangeStatus::CHANGED;
2153 void registerAAs(
bool IsModulePass);
2158 static void registerAAsForFunction(Attributor &A,
const Function &
F);
2162 if (OMPInfoCache.CGSCC && !OMPInfoCache.CGSCC->empty() &&
2163 !OMPInfoCache.CGSCC->contains(&
F))
2168 std::optional<Kernel> &CachedKernel = UniqueKernelMap[&
F];
2170 return *CachedKernel;
2177 return *CachedKernel;
2180 CachedKernel =
nullptr;
2181 if (!
F.hasLocalLinkage()) {
2184 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
2185 return ORA <<
"Potentially unknown OpenMP target region caller.";
2193 auto GetUniqueKernelForUse = [&](
const Use &
U) ->
Kernel {
2196 if (
Cmp->isEquality())
2197 return getUniqueKernelFor(*Cmp);
2203 return getUniqueKernelFor(*CB);
2205 OMPInformationCache::RuntimeFunctionInfo &KernelParallelRFI =
2206 OMPInfoCache.RFIs[OMPRTL___kmpc_parallel_60];
2208 if (OpenMPOpt::getCallIfRegularCall(*
U.getUser(), &KernelParallelRFI))
2209 return getUniqueKernelFor(*CB);
2217 SmallPtrSet<Kernel, 2> PotentialKernels;
2218 OMPInformationCache::foreachUse(
F, [&](
const Use &U) {
2219 PotentialKernels.
insert(GetUniqueKernelForUse(U));
2223 if (PotentialKernels.
size() == 1)
2224 K = *PotentialKernels.
begin();
2227 UniqueKernelMap[&
F] =
K;
2232bool OpenMPOpt::rewriteDeviceCodeStateMachine() {
2233 OMPInformationCache::RuntimeFunctionInfo &KernelParallelRFI =
2234 OMPInfoCache.RFIs[OMPRTL___kmpc_parallel_60];
2237 if (!KernelParallelRFI)
2248 bool UnknownUse =
false;
2249 bool KernelParallelUse =
false;
2250 unsigned NumDirectCalls = 0;
2253 OMPInformationCache::foreachUse(*
F, [&](Use &U) {
2261 ToBeReplacedStateMachineUses.
push_back(&U);
2267 OpenMPOpt::getCallIfRegularCall(*
U.getUser(), &KernelParallelRFI);
2268 const unsigned int WrapperFunctionArgNo = 6;
2269 if (!KernelParallelUse && CI &&
2271 KernelParallelUse =
true;
2272 ToBeReplacedStateMachineUses.
push_back(&U);
2280 if (!KernelParallelUse)
2286 if (UnknownUse || NumDirectCalls != 1 ||
2287 ToBeReplacedStateMachineUses.
size() > 2) {
2288 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
2289 return ORA <<
"Parallel region is used in "
2290 << (UnknownUse ?
"unknown" :
"unexpected")
2291 <<
" ways. Will not attempt to rewrite the state machine.";
2301 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
2302 return ORA <<
"Parallel region is not called from a unique kernel. "
2303 "Will not attempt to rewrite the state machine.";
2315 Type *Int8Ty = Type::getInt8Ty(
M.getContext());
2317 auto *
ID =
new GlobalVariable(
2321 for (Use *U : ToBeReplacedStateMachineUses)
2323 ID,
U->get()->getType()));
2325 ++NumOpenMPParallelRegionsReplacedInGPUStateMachine;
2333bool OpenMPOpt::removeSPMDParallelWrappers() {
2335 if (OMPInfoCache.SPMDizedKernels.empty())
2338 OMPInformationCache::RuntimeFunctionInfo &KernelParallelRFI =
2339 OMPInfoCache.RFIs[OMPRTL___kmpc_parallel_60];
2340 if (!KernelParallelRFI || !KernelParallelRFI.Declaration)
2343 constexpr unsigned WrapperFunctionArgNo = 6;
2345 for (User *U : KernelParallelRFI.Declaration->
users()) {
2348 CI->
arg_size() <= WrapperFunctionArgNo)
2362 if (!K || !OMPInfoCache.SPMDizedKernels.contains(K))
2366 WrapperFunctionArgNo,
2375struct AAICVTracker :
public StateWrapper<BooleanState, AbstractAttribute> {
2376 using Base = StateWrapper<BooleanState, AbstractAttribute>;
2377 AAICVTracker(
const IRPosition &IRP, Attributor &
A) :
Base(IRP) {}
2380 bool isAssumedTracked()
const {
return getAssumed(); }
2383 bool isKnownTracked()
const {
return getAssumed(); }
2386 static AAICVTracker &createForPosition(
const IRPosition &IRP, Attributor &
A);
2390 const Instruction *
I,
2391 Attributor &
A)
const {
2392 return std::nullopt;
2398 virtual std::optional<Value *>
2406 StringRef
getName()
const override {
return "AAICVTracker"; }
2409 const char *getIdAddr()
const override {
return &ID; }
2412 static bool classof(
const AbstractAttribute *AA) {
2416 static const char ID;
2419struct AAICVTrackerFunction :
public AAICVTracker {
2420 AAICVTrackerFunction(
const IRPosition &IRP, Attributor &
A)
2421 : AAICVTracker(IRP,
A) {}
2424 const std::string getAsStr(Attributor *)
const override {
2425 return "ICVTrackerFunction";
2429 void trackStatistics()
const override {}
2433 return ChangeStatus::UNCHANGED;
2438 InternalControlVar::ICV___last>
2439 ICVReplacementValuesMap;
2446 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
2449 auto &SetterRFI = OMPInfoCache.RFIs[OMPInfoCache.ICVs[ICV].Setter];
2451 auto &ValuesMap = ICVReplacementValuesMap[ICV];
2453 CallInst *CI = OpenMPOpt::getCallIfRegularCall(U);
2459 if (ValuesMap.insert(std::make_pair(CI, CI->
getArgOperand(0))).second)
2460 HasChanged = ChangeStatus::CHANGED;
2466 std::optional<Value *> ReplVal = getValueForCall(
A,
I, ICV);
2467 if (ReplVal && ValuesMap.insert(std::make_pair(&
I, *ReplVal)).second)
2468 HasChanged = ChangeStatus::CHANGED;
2474 SetterRFI.foreachUse(TrackValues,
F);
2476 bool UsedAssumedInformation =
false;
2477 A.checkForAllInstructions(CallCheck, *
this, {Instruction::Call},
2478 UsedAssumedInformation,
2484 if (HasChanged == ChangeStatus::CHANGED)
2485 ValuesMap.try_emplace(Entry);
2493 std::optional<Value *> getValueForCall(Attributor &
A,
const Instruction &
I,
2497 if (!CB || CB->
hasFnAttr(
"no_openmp") ||
2500 return std::nullopt;
2502 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
2503 auto &GetterRFI = OMPInfoCache.RFIs[OMPInfoCache.ICVs[ICV].Getter];
2504 auto &SetterRFI = OMPInfoCache.RFIs[OMPInfoCache.ICVs[ICV].Setter];
2508 if (CalledFunction ==
nullptr)
2510 if (CalledFunction == GetterRFI.Declaration)
2511 return std::nullopt;
2512 if (CalledFunction == SetterRFI.Declaration) {
2513 if (ICVReplacementValuesMap[ICV].
count(&
I))
2514 return ICVReplacementValuesMap[ICV].lookup(&
I);
2523 const auto *ICVTrackingAA =
A.getAAFor<AAICVTracker>(
2526 if (ICVTrackingAA->isAssumedTracked()) {
2527 std::optional<Value *> URV =
2528 ICVTrackingAA->getUniqueReplacementValue(ICV);
2539 std::optional<Value *>
2541 return std::nullopt;
2546 const Instruction *
I,
2547 Attributor &
A)
const override {
2548 const auto &ValuesMap = ICVReplacementValuesMap[ICV];
2549 if (ValuesMap.count(
I))
2550 return ValuesMap.lookup(
I);
2553 SmallPtrSet<const Instruction *, 16> Visited;
2556 std::optional<Value *> ReplVal;
2558 while (!Worklist.
empty()) {
2560 if (!Visited.
insert(CurrInst).second)
2568 if (ValuesMap.count(CurrInst)) {
2569 std::optional<Value *> NewReplVal = ValuesMap.lookup(CurrInst);
2572 ReplVal = NewReplVal;
2578 if (ReplVal != NewReplVal)
2584 std::optional<Value *> NewReplVal = getValueForCall(
A, *CurrInst, ICV);
2590 ReplVal = NewReplVal;
2596 if (ReplVal != NewReplVal)
2601 if (CurrBB ==
I->getParent() && ReplVal)
2606 if (
const Instruction *Terminator = Pred->getTerminator())
2614struct AAICVTrackerFunctionReturned : AAICVTracker {
2615 AAICVTrackerFunctionReturned(
const IRPosition &IRP, Attributor &
A)
2616 : AAICVTracker(IRP,
A) {}
2619 const std::string getAsStr(Attributor *)
const override {
2620 return "ICVTrackerFunctionReturned";
2624 void trackStatistics()
const override {}
2628 return ChangeStatus::UNCHANGED;
2633 InternalControlVar::ICV___last>
2634 ICVReplacementValuesMap;
2637 std::optional<Value *>
2639 return ICVReplacementValuesMap[ICV];
2644 const auto *ICVTrackingAA =
A.getAAFor<AAICVTracker>(
2647 if (!ICVTrackingAA->isAssumedTracked())
2648 return indicatePessimisticFixpoint();
2651 std::optional<Value *> &ReplVal = ICVReplacementValuesMap[ICV];
2652 std::optional<Value *> UniqueICVValue;
2655 std::optional<Value *> NewReplVal =
2656 ICVTrackingAA->getReplacementValue(ICV, &
I,
A);
2659 if (UniqueICVValue && UniqueICVValue != NewReplVal)
2662 UniqueICVValue = NewReplVal;
2667 bool UsedAssumedInformation =
false;
2668 if (!
A.checkForAllInstructions(CheckReturnInst, *
this, {Instruction::Ret},
2669 UsedAssumedInformation,
2671 UniqueICVValue =
nullptr;
2673 if (UniqueICVValue == ReplVal)
2676 ReplVal = UniqueICVValue;
2677 Changed = ChangeStatus::CHANGED;
2684struct AAICVTrackerCallSite : AAICVTracker {
2685 AAICVTrackerCallSite(
const IRPosition &IRP, Attributor &
A)
2686 : AAICVTracker(IRP,
A) {}
2689 assert(getAnchorScope() &&
"Expected anchor function");
2693 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
2695 auto ICVInfo = OMPInfoCache.ICVs[ICV];
2696 auto &Getter = OMPInfoCache.RFIs[ICVInfo.Getter];
2697 if (Getter.Declaration == getAssociatedFunction()) {
2698 AssociatedICV = ICVInfo.Kind;
2704 indicatePessimisticFixpoint();
2708 if (!ReplVal || !*ReplVal)
2709 return ChangeStatus::UNCHANGED;
2712 A.deleteAfterManifest(*getCtxI());
2714 return ChangeStatus::CHANGED;
2718 const std::string getAsStr(Attributor *)
const override {
2719 return "ICVTrackerCallSite";
2723 void trackStatistics()
const override {}
2726 std::optional<Value *> ReplVal;
2729 const auto *ICVTrackingAA =
A.getAAFor<AAICVTracker>(
2733 if (!ICVTrackingAA->isAssumedTracked())
2734 return indicatePessimisticFixpoint();
2736 std::optional<Value *> NewReplVal =
2737 ICVTrackingAA->getReplacementValue(AssociatedICV, getCtxI(),
A);
2739 if (ReplVal == NewReplVal)
2740 return ChangeStatus::UNCHANGED;
2742 ReplVal = NewReplVal;
2743 return ChangeStatus::CHANGED;
2748 std::optional<Value *>
2754struct AAICVTrackerCallSiteReturned : AAICVTracker {
2755 AAICVTrackerCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
2756 : AAICVTracker(IRP,
A) {}
2759 const std::string getAsStr(Attributor *)
const override {
2760 return "ICVTrackerCallSiteReturned";
2764 void trackStatistics()
const override {}
2768 return ChangeStatus::UNCHANGED;
2773 InternalControlVar::ICV___last>
2774 ICVReplacementValuesMap;
2778 std::optional<Value *>
2780 return ICVReplacementValuesMap[ICV];
2785 const auto *ICVTrackingAA =
A.getAAFor<AAICVTracker>(
2787 DepClassTy::REQUIRED);
2790 if (!ICVTrackingAA->isAssumedTracked())
2791 return indicatePessimisticFixpoint();
2794 std::optional<Value *> &ReplVal = ICVReplacementValuesMap[ICV];
2795 std::optional<Value *> NewReplVal =
2796 ICVTrackingAA->getUniqueReplacementValue(ICV);
2798 if (ReplVal == NewReplVal)
2801 ReplVal = NewReplVal;
2802 Changed = ChangeStatus::CHANGED;
2810static bool hasFunctionEndAsUniqueSuccessor(
const BasicBlock *BB) {
2816 return hasFunctionEndAsUniqueSuccessor(
Successor);
2819struct AAExecutionDomainFunction :
public AAExecutionDomain {
2820 AAExecutionDomainFunction(
const IRPosition &IRP, Attributor &
A)
2821 : AAExecutionDomain(IRP,
A) {}
2823 ~AAExecutionDomainFunction()
override {
delete RPOT; }
2827 assert(
F &&
"Expected anchor function");
2828 RPOT =
new ReversePostOrderTraversal<Function *>(
F);
2831 const std::string getAsStr(Attributor *)
const override {
2832 unsigned TotalBlocks = 0, InitialThreadBlocks = 0, AlignedBlocks = 0;
2833 for (
auto &It : BEDMap) {
2837 InitialThreadBlocks += It.getSecond().IsExecutedByInitialThreadOnly;
2838 AlignedBlocks += It.getSecond().IsReachedFromAlignedBarrierOnly &&
2839 It.getSecond().IsReachingAlignedBarrierOnly;
2841 return "[AAExecutionDomain] " + std::to_string(InitialThreadBlocks) +
"/" +
2842 std::to_string(AlignedBlocks) +
" of " +
2843 std::to_string(TotalBlocks) +
2844 " executed by initial thread / aligned";
2848 void trackStatistics()
const override {}
2852 for (
const BasicBlock &BB : *getAnchorScope()) {
2853 if (!isExecutedByInitialThreadOnly(BB))
2855 dbgs() <<
TAG <<
" Basic block @" << getAnchorScope()->getName() <<
" "
2856 << BB.
getName() <<
" is executed by a single thread.\n";
2865 SmallPtrSet<CallBase *, 16> DeletedBarriers;
2866 auto HandleAlignedBarrier = [&](CallBase *CB) {
2867 const ExecutionDomainTy &ED = CB ? CEDMap[{CB, PRE}] : BEDMap[
nullptr];
2868 if (!ED.IsReachedFromAlignedBarrierOnly ||
2869 ED.EncounteredNonLocalSideEffect)
2871 if (!ED.EncounteredAssumes.empty() && !
A.isModulePass())
2882 DeletedBarriers.
insert(CB);
2883 A.deleteAfterManifest(*CB);
2884 ++NumBarriersEliminated;
2885 Changed = ChangeStatus::CHANGED;
2886 }
else if (!ED.AlignedBarriers.empty()) {
2887 Changed = ChangeStatus::CHANGED;
2889 ED.AlignedBarriers.end());
2890 SmallSetVector<CallBase *, 16> Visited;
2891 while (!Worklist.
empty()) {
2893 if (!Visited.
insert(LastCB))
2897 if (!hasFunctionEndAsUniqueSuccessor(LastCB->
getParent()))
2899 if (!DeletedBarriers.
count(LastCB)) {
2900 ++NumBarriersEliminated;
2901 A.deleteAfterManifest(*LastCB);
2907 const ExecutionDomainTy &LastED = CEDMap[{LastCB, PRE}];
2908 Worklist.
append(LastED.AlignedBarriers.begin(),
2909 LastED.AlignedBarriers.end());
2915 if (!ED.EncounteredAssumes.empty() && (CB || !ED.AlignedBarriers.empty()))
2916 for (
auto *AssumeCB : ED.EncounteredAssumes)
2917 A.deleteAfterManifest(*AssumeCB);
2920 for (
auto *CB : AlignedBarriers)
2921 HandleAlignedBarrier(CB);
2925 HandleAlignedBarrier(
nullptr);
2930 bool isNoOpFence(
const FenceInst &FI)
const override {
2931 return getState().isValidState() && !NonNoOpFences.count(&FI);
2937 mergeInPredecessorBarriersAndAssumptions(Attributor &
A, ExecutionDomainTy &ED,
2938 const ExecutionDomainTy &PredED);
2943 bool mergeInPredecessor(Attributor &
A, ExecutionDomainTy &ED,
2944 const ExecutionDomainTy &PredED,
2945 bool InitialEdgeOnly =
false);
2948 bool handleCallees(Attributor &
A, ExecutionDomainTy &EntryBBED);
2955 bool isExecutedByInitialThreadOnly(
const BasicBlock &BB)
const override {
2956 if (!isValidState())
2958 assert(BB.
getParent() == getAnchorScope() &&
"Block is out of scope!");
2959 return BEDMap.lookup(&BB).IsExecutedByInitialThreadOnly;
2962 bool isExecutedInAlignedRegion(Attributor &
A,
2963 const Instruction &
I)
const override {
2964 assert(
I.getFunction() == getAnchorScope() &&
2965 "Instruction is out of scope!");
2966 if (!isValidState())
2969 bool ForwardIsOk =
true;
2978 if (CB != &
I && AlignedBarriers.contains(
const_cast<CallBase *
>(CB)))
2980 const auto &It = CEDMap.find({CB, PRE});
2981 if (It == CEDMap.end())
2983 if (!It->getSecond().IsReachingAlignedBarrierOnly)
2984 ForwardIsOk =
false;
2988 if (!CurI && !BEDMap.lookup(
I.getParent()).IsReachingAlignedBarrierOnly)
2989 ForwardIsOk =
false;
2997 if (CB != &
I && AlignedBarriers.contains(
const_cast<CallBase *
>(CB)))
2999 const auto &It = CEDMap.find({CB, POST});
3000 if (It == CEDMap.end())
3002 if (It->getSecond().IsReachedFromAlignedBarrierOnly)
3015 return BEDMap.lookup(
nullptr).IsReachedFromAlignedBarrierOnly;
3017 return BEDMap.lookup(PredBB).IsReachedFromAlignedBarrierOnly;
3027 ExecutionDomainTy getExecutionDomain(
const BasicBlock &BB)
const override {
3029 "No request should be made against an invalid state!");
3030 return BEDMap.lookup(&BB);
3032 std::pair<ExecutionDomainTy, ExecutionDomainTy>
3033 getExecutionDomain(
const CallBase &CB)
const override {
3035 "No request should be made against an invalid state!");
3036 return {CEDMap.lookup({&CB, PRE}), CEDMap.lookup({&CB, POST})};
3038 ExecutionDomainTy getFunctionExecutionDomain()
const override {
3040 "No request should be made against an invalid state!");
3041 return InterProceduralED;
3047 static bool isInitialThreadOnlyEdge(Attributor &
A, CondBrInst *
Edge,
3048 BasicBlock &SuccessorBB) {
3051 if (
Edge->getSuccessor(0) != &SuccessorBB)
3055 if (!Cmp || !
Cmp->isTrueWhenEqual() || !
Cmp->isEquality())
3063 if (
C->isAllOnesValue()) {
3065 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
3066 auto &RFI = OMPInfoCache.RFIs[OMPRTL___kmpc_target_init];
3067 CB = CB ? OpenMPOpt::getCallIfRegularCall(*CB, &RFI) : nullptr;
3070 ConstantStruct *KernelEnvC =
3072 ConstantInt *ExecModeC =
3073 KernelInfo::getExecModeFromKernelEnvironment(KernelEnvC);
3080 if (
II->getIntrinsicID() == Intrinsic::nvvm_read_ptx_sreg_tid_x)
3085 if (
II->getIntrinsicID() == Intrinsic::amdgcn_workitem_id_x)
3093 ExecutionDomainTy InterProceduralED;
3097 DenseMap<const BasicBlock *, ExecutionDomainTy> BEDMap;
3098 DenseMap<PointerIntPair<const CallBase *, 1, Direction>, ExecutionDomainTy>
3100 SmallSetVector<CallBase *, 16> AlignedBarriers;
3102 ReversePostOrderTraversal<Function *> *RPOT =
nullptr;
3105 static bool setAndRecord(
bool &R,
bool V) {
3113 SmallPtrSet<const FenceInst *, 8> NonNoOpFences;
3116void AAExecutionDomainFunction::mergeInPredecessorBarriersAndAssumptions(
3117 Attributor &
A, ExecutionDomainTy &ED,
const ExecutionDomainTy &PredED) {
3118 for (
auto *EA : PredED.EncounteredAssumes)
3119 ED.addAssumeInst(
A, *EA);
3121 for (
auto *AB : PredED.AlignedBarriers)
3122 ED.addAlignedBarrier(
A, *AB);
3125bool AAExecutionDomainFunction::mergeInPredecessor(
3126 Attributor &
A, ExecutionDomainTy &ED,
const ExecutionDomainTy &PredED,
3127 bool InitialEdgeOnly) {
3131 setAndRecord(ED.IsExecutedByInitialThreadOnly,
3132 InitialEdgeOnly || (PredED.IsExecutedByInitialThreadOnly &&
3133 ED.IsExecutedByInitialThreadOnly));
3135 Changed |= setAndRecord(ED.IsReachedFromAlignedBarrierOnly,
3136 ED.IsReachedFromAlignedBarrierOnly &&
3137 PredED.IsReachedFromAlignedBarrierOnly);
3138 Changed |= setAndRecord(ED.EncounteredNonLocalSideEffect,
3139 ED.EncounteredNonLocalSideEffect |
3140 PredED.EncounteredNonLocalSideEffect);
3142 if (ED.IsReachedFromAlignedBarrierOnly)
3143 mergeInPredecessorBarriersAndAssumptions(
A, ED, PredED);
3145 ED.clearAssumeInstAndAlignedBarriers();
3149bool AAExecutionDomainFunction::handleCallees(Attributor &
A,
3150 ExecutionDomainTy &EntryBBED) {
3152 auto PredForCallSite = [&](AbstractCallSite ACS) {
3153 const auto *EDAA =
A.getAAFor<AAExecutionDomain>(
3155 DepClassTy::OPTIONAL);
3156 if (!EDAA || !EDAA->getState().isValidState())
3159 EDAA->getExecutionDomain(*
cast<CallBase>(ACS.getInstruction())));
3163 ExecutionDomainTy ExitED;
3164 bool AllCallSitesKnown;
3165 if (
A.checkForAllCallSites(PredForCallSite, *
this,
3167 AllCallSitesKnown)) {
3168 for (
const auto &[CSInED, CSOutED] : CallSiteEDs) {
3169 mergeInPredecessor(
A, EntryBBED, CSInED);
3170 ExitED.IsReachingAlignedBarrierOnly &=
3171 CSOutED.IsReachingAlignedBarrierOnly;
3178 EntryBBED.IsExecutedByInitialThreadOnly =
false;
3179 EntryBBED.IsReachedFromAlignedBarrierOnly =
true;
3180 EntryBBED.EncounteredNonLocalSideEffect =
false;
3181 ExitED.IsReachingAlignedBarrierOnly =
false;
3183 EntryBBED.IsExecutedByInitialThreadOnly =
false;
3184 EntryBBED.IsReachedFromAlignedBarrierOnly =
false;
3185 EntryBBED.EncounteredNonLocalSideEffect =
true;
3186 ExitED.IsReachingAlignedBarrierOnly =
false;
3191 auto &FnED = BEDMap[
nullptr];
3192 Changed |= setAndRecord(FnED.IsReachedFromAlignedBarrierOnly,
3193 FnED.IsReachedFromAlignedBarrierOnly &
3194 EntryBBED.IsReachedFromAlignedBarrierOnly);
3195 Changed |= setAndRecord(FnED.IsReachingAlignedBarrierOnly,
3196 FnED.IsReachingAlignedBarrierOnly &
3197 ExitED.IsReachingAlignedBarrierOnly);
3198 Changed |= setAndRecord(FnED.IsExecutedByInitialThreadOnly,
3199 EntryBBED.IsExecutedByInitialThreadOnly);
3203ChangeStatus AAExecutionDomainFunction::updateImpl(Attributor &
A) {
3210 auto HandleAlignedBarrier = [&](CallBase &CB, ExecutionDomainTy &ED) {
3211 Changed |= AlignedBarriers.insert(&CB);
3213 auto &CallInED = CEDMap[{&CB, PRE}];
3214 Changed |= mergeInPredecessor(
A, CallInED, ED);
3215 CallInED.IsReachingAlignedBarrierOnly =
true;
3217 ED.EncounteredNonLocalSideEffect =
false;
3218 ED.IsReachedFromAlignedBarrierOnly =
true;
3220 ED.clearAssumeInstAndAlignedBarriers();
3221 ED.addAlignedBarrier(
A, CB);
3222 auto &CallOutED = CEDMap[{&CB, POST}];
3223 Changed |= mergeInPredecessor(
A, CallOutED, ED);
3227 A.getAAFor<AAIsDead>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
3233 SmallVector<Instruction *> SyncInstWorklist;
3234 for (
auto &RIt : *RPOT) {
3237 bool IsEntryBB = &BB == &EntryBB;
3240 bool AlignedBarrierLastInBlock = IsEntryBB && IsKernel;
3241 bool IsExplicitlyAligned = IsEntryBB && IsKernel;
3242 ExecutionDomainTy ED;
3249 if (LivenessAA && LivenessAA->isAssumedDead(&BB))
3253 if (LivenessAA && LivenessAA->isEdgeDead(PredBB, &BB))
3255 bool InitialEdgeOnly = isInitialThreadOnlyEdge(
3257 mergeInPredecessor(
A, ED, BEDMap[PredBB], InitialEdgeOnly);
3263 for (Instruction &
I : BB) {
3264 bool UsedAssumedInformation;
3265 if (
A.isAssumedDead(
I, *
this, LivenessAA, UsedAssumedInformation,
3266 false, DepClassTy::OPTIONAL,
3274 ED.addAssumeInst(
A, *AI);
3278 if (
II->isAssumeLikeIntrinsic())
3283 if (!ED.EncounteredNonLocalSideEffect) {
3285 if (ED.IsReachedFromAlignedBarrierOnly)
3290 case AtomicOrdering::NotAtomic:
3292 case AtomicOrdering::Unordered:
3294 case AtomicOrdering::Monotonic:
3296 case AtomicOrdering::Acquire:
3298 case AtomicOrdering::Release:
3300 case AtomicOrdering::AcquireRelease:
3302 case AtomicOrdering::SequentiallyConsistent:
3306 NonNoOpFences.insert(FI);
3311 bool IsAlignedBarrier =
3315 AlignedBarrierLastInBlock &= IsNoSync;
3316 IsExplicitlyAligned &= IsNoSync;
3322 if (IsAlignedBarrier) {
3323 HandleAlignedBarrier(*CB, ED);
3324 AlignedBarrierLastInBlock =
true;
3325 IsExplicitlyAligned =
true;
3331 if (!ED.EncounteredNonLocalSideEffect &&
3333 ED.EncounteredNonLocalSideEffect =
true;
3335 ED.IsReachedFromAlignedBarrierOnly =
false;
3343 auto &CallInED = CEDMap[{CB, PRE}];
3344 Changed |= mergeInPredecessor(
A, CallInED, ED);
3350 if (!IsNoSync && Callee && !
Callee->isDeclaration()) {
3351 const auto *EDAA =
A.getAAFor<AAExecutionDomain>(
3353 if (EDAA && EDAA->getState().isValidState()) {
3354 const auto &CalleeED = EDAA->getFunctionExecutionDomain();
3355 ED.IsReachedFromAlignedBarrierOnly =
3356 CalleeED.IsReachedFromAlignedBarrierOnly;
3357 AlignedBarrierLastInBlock = ED.IsReachedFromAlignedBarrierOnly;
3358 if (IsNoSync || !CalleeED.IsReachedFromAlignedBarrierOnly)
3359 ED.EncounteredNonLocalSideEffect |=
3360 CalleeED.EncounteredNonLocalSideEffect;
3362 ED.EncounteredNonLocalSideEffect =
3363 CalleeED.EncounteredNonLocalSideEffect;
3364 if (!CalleeED.IsReachingAlignedBarrierOnly) {
3366 setAndRecord(CallInED.IsReachingAlignedBarrierOnly,
false);
3369 if (CalleeED.IsReachedFromAlignedBarrierOnly)
3370 mergeInPredecessorBarriersAndAssumptions(
A, ED, CalleeED);
3371 auto &CallOutED = CEDMap[{CB, POST}];
3372 Changed |= mergeInPredecessor(
A, CallOutED, ED);
3377 ED.IsReachedFromAlignedBarrierOnly =
false;
3378 Changed |= setAndRecord(CallInED.IsReachingAlignedBarrierOnly,
false);
3381 AlignedBarrierLastInBlock &= ED.IsReachedFromAlignedBarrierOnly;
3383 auto &CallOutED = CEDMap[{CB, POST}];
3384 Changed |= mergeInPredecessor(
A, CallOutED, ED);
3387 if (!
I.mayHaveSideEffects() && !
I.mayReadFromMemory())
3393 const auto *MemAA =
A.getAAFor<AAMemoryLocation>(
3401 if (MemAA && MemAA->getState().isValidState() &&
3402 MemAA->checkForAllAccessesToMemoryKind(
3407 auto &InfoCache =
A.getInfoCache();
3408 if (!
I.mayHaveSideEffects() && InfoCache.isOnlyUsedByAssume(
I))
3412 if (LI->hasMetadata(LLVMContext::MD_invariant_load))
3415 if (!ED.EncounteredNonLocalSideEffect &&
3417 ED.EncounteredNonLocalSideEffect =
true;
3420 bool IsEndAndNotReachingAlignedBarriersOnly =
false;
3422 !BB.getTerminator()->getNumSuccessors()) {
3424 Changed |= mergeInPredecessor(
A, InterProceduralED, ED);
3426 auto &FnED = BEDMap[
nullptr];
3427 if (IsKernel && !IsExplicitlyAligned)
3428 FnED.IsReachingAlignedBarrierOnly =
false;
3429 Changed |= mergeInPredecessor(
A, FnED, ED);
3431 if (!FnED.IsReachingAlignedBarrierOnly) {
3432 IsEndAndNotReachingAlignedBarriersOnly =
true;
3433 SyncInstWorklist.
push_back(BB.getTerminator());
3434 auto &BBED = BEDMap[&BB];
3435 Changed |= setAndRecord(BBED.IsReachingAlignedBarrierOnly,
false);
3439 ExecutionDomainTy &StoredED = BEDMap[&BB];
3440 ED.IsReachingAlignedBarrierOnly = StoredED.IsReachingAlignedBarrierOnly &
3441 !IsEndAndNotReachingAlignedBarriersOnly;
3447 if (ED.IsExecutedByInitialThreadOnly !=
3448 StoredED.IsExecutedByInitialThreadOnly ||
3449 ED.IsReachedFromAlignedBarrierOnly !=
3450 StoredED.IsReachedFromAlignedBarrierOnly ||
3451 ED.EncounteredNonLocalSideEffect !=
3452 StoredED.EncounteredNonLocalSideEffect)
3456 StoredED = std::move(ED);
3461 SmallSetVector<BasicBlock *, 16> Visited;
3462 while (!SyncInstWorklist.
empty()) {
3465 bool HitAlignedBarrierOrKnownEnd =
false;
3470 auto &CallOutED = CEDMap[{CB, POST}];
3471 Changed |= setAndRecord(CallOutED.IsReachingAlignedBarrierOnly,
false);
3472 auto &CallInED = CEDMap[{CB, PRE}];
3473 HitAlignedBarrierOrKnownEnd =
3474 AlignedBarriers.count(CB) || !CallInED.IsReachingAlignedBarrierOnly;
3475 if (HitAlignedBarrierOrKnownEnd)
3477 Changed |= setAndRecord(CallInED.IsReachingAlignedBarrierOnly,
false);
3479 if (HitAlignedBarrierOrKnownEnd)
3483 if (LivenessAA && LivenessAA->isEdgeDead(PredBB, SyncBB))
3485 if (!Visited.
insert(PredBB))
3487 auto &PredED = BEDMap[PredBB];
3488 if (setAndRecord(PredED.IsReachingAlignedBarrierOnly,
false)) {
3490 SyncInstWorklist.
push_back(PredBB->getTerminator());
3493 if (SyncBB != &EntryBB)
3496 setAndRecord(InterProceduralED.IsReachingAlignedBarrierOnly,
false);
3499 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
3504struct AAHeapToShared :
public StateWrapper<BooleanState, AbstractAttribute> {
3505 using Base = StateWrapper<BooleanState, AbstractAttribute>;
3506 AAHeapToShared(
const IRPosition &IRP, Attributor &
A) :
Base(IRP) {}
3509 static AAHeapToShared &createForPosition(
const IRPosition &IRP,
3513 virtual bool isAssumedHeapToShared(CallBase &CB)
const = 0;
3517 virtual bool isAssumedHeapToSharedRemovedFree(CallBase &CB)
const = 0;
3520 StringRef
getName()
const override {
return "AAHeapToShared"; }
3523 const char *getIdAddr()
const override {
return &ID; }
3527 static bool classof(
const AbstractAttribute *AA) {
3532 static const char ID;
3535struct AAHeapToSharedFunction :
public AAHeapToShared {
3536 AAHeapToSharedFunction(
const IRPosition &IRP, Attributor &
A)
3537 : AAHeapToShared(IRP,
A) {}
3539 const std::string getAsStr(Attributor *)
const override {
3540 return "[AAHeapToShared] " + std::to_string(MallocCalls.size()) +
3541 " malloc calls eligible.";
3545 void trackStatistics()
const override {}
3549 void findPotentialRemovedFreeCalls(Attributor &
A) {
3550 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
3551 auto &FreeRFI = OMPInfoCache.RFIs[OMPRTL___kmpc_free_shared];
3553 PotentialRemovedFreeCalls.clear();
3555 for (CallBase *CB : MallocCalls) {
3557 for (
auto *U : CB->
users()) {
3559 if (
C &&
C->getCalledFunction() == FreeRFI.Declaration)
3563 if (FreeCalls.
size() != 1)
3566 PotentialRemovedFreeCalls.insert(FreeCalls.
front());
3572 indicatePessimisticFixpoint();
3576 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
3577 auto &RFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
3578 if (!RFI.Declaration)
3582 [](
const IRPosition &,
const AbstractAttribute *,
3583 bool &) -> std::optional<Value *> {
return nullptr; };
3586 const OMPInformationCache::RuntimeFunctionInfo::UseVector *
Uses =
3587 RFI.getUseVector(*
F);
3591 for (Use *U : *
Uses)
3593 MallocCalls.insert(CB);
3598 findPotentialRemovedFreeCalls(
A);
3601 bool isAssumedHeapToShared(CallBase &CB)
const override {
3602 return isValidState() && MallocCalls.count(&CB);
3605 bool isAssumedHeapToSharedRemovedFree(CallBase &CB)
const override {
3606 return isValidState() && PotentialRemovedFreeCalls.count(&CB);
3610 if (MallocCalls.empty())
3611 return ChangeStatus::UNCHANGED;
3613 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
3614 auto &FreeCall = OMPInfoCache.RFIs[OMPRTL___kmpc_free_shared];
3618 DepClassTy::OPTIONAL);
3621 for (CallBase *CB : MallocCalls) {
3623 if (HS &&
HS->isAssumedHeapToStack(*CB))
3628 for (
auto *U : CB->
users()) {
3630 if (
C &&
C->getCalledFunction() == FreeCall.Declaration)
3633 if (FreeCalls.
size() != 1)
3640 <<
" with shared memory."
3641 <<
" Shared memory usage is limited to "
3647 <<
" with " << AllocSize->getZExtValue()
3648 <<
" bytes of shared memory\n");
3653 Type *Int8Ty = Type::getInt8Ty(
M->getContext());
3654 Type *Int8ArrTy = ArrayType::get(Int8Ty, AllocSize->getZExtValue());
3655 auto *SharedMem =
new GlobalVariable(
3659 static_cast<unsigned>(AddressSpace::Shared));
3661 SharedMem, PointerType::getUnqual(
M->getContext()));
3663 auto Remark = [&](OptimizationRemark
OR) {
3664 return OR <<
"Replaced globalized variable with "
3665 <<
ore::NV(
"SharedMemory", AllocSize->getZExtValue())
3666 << (AllocSize->isOne() ?
" byte " :
" bytes ")
3667 <<
"of shared memory.";
3669 A.emitRemark<OptimizationRemark>(CB,
"OMP111",
Remark);
3671 MaybeAlign
Alignment = CB->getRetAlign();
3673 "HeapToShared on allocation without alignment attribute");
3677 A.deleteAfterManifest(*CB);
3678 A.deleteAfterManifest(*FreeCalls.
front());
3680 SharedMemoryUsed += AllocSize->getZExtValue();
3681 NumBytesMovedToSharedMemory = SharedMemoryUsed;
3682 Changed = ChangeStatus::CHANGED;
3689 if (MallocCalls.empty())
3690 return indicatePessimisticFixpoint();
3691 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
3692 auto &RFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
3693 if (!RFI.Declaration)
3694 return ChangeStatus::UNCHANGED;
3698 auto NumMallocCalls = MallocCalls.size();
3701 for (User *U : RFI.Declaration->
users()) {
3703 if (CB->getCaller() !=
F)
3705 if (!MallocCalls.count(CB))
3708 MallocCalls.remove(CB);
3711 const auto *ED =
A.getAAFor<AAExecutionDomain>(
3713 if (!ED || !ED->isExecutedByInitialThreadOnly(*CB))
3714 MallocCalls.remove(CB);
3718 findPotentialRemovedFreeCalls(
A);
3720 if (NumMallocCalls != MallocCalls.size())
3721 return ChangeStatus::CHANGED;
3723 return ChangeStatus::UNCHANGED;
3727 SmallSetVector<CallBase *, 4> MallocCalls;
3729 SmallPtrSet<CallBase *, 4> PotentialRemovedFreeCalls;
3731 unsigned SharedMemoryUsed = 0;
3734struct AAKernelInfo :
public StateWrapper<KernelInfoState, AbstractAttribute> {
3735 using Base = StateWrapper<KernelInfoState, AbstractAttribute>;
3736 AAKernelInfo(
const IRPosition &IRP, Attributor &
A) :
Base(IRP) {}
3740 static bool requiresCalleeForCallBase() {
return false; }
3743 void trackStatistics()
const override {}
3746 const std::string getAsStr(Attributor *)
const override {
3747 if (!isValidState())
3749 return std::string(SPMDCompatibilityTracker.isAssumed() ?
"SPMD"
3751 std::string(SPMDCompatibilityTracker.isAtFixpoint() ?
" [FIX]"
3753 std::string(
" #PRs: ") +
3754 (ReachedKnownParallelRegions.isValidState()
3755 ? std::to_string(ReachedKnownParallelRegions.size())
3757 ", #Unknown PRs: " +
3758 (ReachedUnknownParallelRegions.isValidState()
3759 ? std::to_string(ReachedUnknownParallelRegions.size())
3761 ", #Reaching Kernels: " +
3762 (ReachingKernelEntries.isValidState()
3763 ? std::to_string(ReachingKernelEntries.size())
3766 (ParallelLevels.isValidState()
3767 ? std::to_string(ParallelLevels.size())
3769 ", NestedPar: " + (NestedParallelism ?
"yes" :
"no");
3773 static AAKernelInfo &createForPosition(
const IRPosition &IRP, Attributor &
A);
3776 StringRef
getName()
const override {
return "AAKernelInfo"; }
3779 const char *getIdAddr()
const override {
return &ID; }
3782 static bool classof(
const AbstractAttribute *AA) {
3786 static const char ID;
3791struct AAKernelInfoFunction : AAKernelInfo {
3792 AAKernelInfoFunction(
const IRPosition &IRP, Attributor &
A)
3793 : AAKernelInfo(IRP,
A) {}
3795 SmallPtrSet<Instruction *, 4> GuardedInstructions;
3797 SmallPtrSetImpl<Instruction *> &getGuardedInstructions() {
3798 return GuardedInstructions;
3801 void setConfigurationOfKernelEnvironment(ConstantStruct *ConfigC) {
3803 KernelEnvC, ConfigC, {KernelInfo::ConfigurationIdx});
3804 assert(NewKernelEnvC &&
"Failed to create new kernel environment");
3808#define KERNEL_ENVIRONMENT_CONFIGURATION_SETTER(MEMBER) \
3809 void set##MEMBER##OfKernelEnvironment(ConstantInt *NewVal) { \
3810 ConstantStruct *ConfigC = \
3811 KernelInfo::getConfigurationFromKernelEnvironment(KernelEnvC); \
3812 Constant *NewConfigC = ConstantFoldInsertValueInstruction( \
3813 ConfigC, NewVal, {KernelInfo::MEMBER##Idx}); \
3814 assert(NewConfigC && "Failed to create new configuration environment"); \
3815 setConfigurationOfKernelEnvironment(cast<ConstantStruct>(NewConfigC)); \
3826#undef KERNEL_ENVIRONMENT_CONFIGURATION_SETTER
3833 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
3837 OMPInformationCache::RuntimeFunctionInfo &InitRFI =
3838 OMPInfoCache.RFIs[OMPRTL___kmpc_target_init];
3839 OMPInformationCache::RuntimeFunctionInfo &DeinitRFI =
3840 OMPInfoCache.RFIs[OMPRTL___kmpc_target_deinit];
3844 auto StoreCallBase = [](
Use &U,
3845 OMPInformationCache::RuntimeFunctionInfo &RFI,
3847 CallBase *CB = OpenMPOpt::getCallIfRegularCall(U, &RFI);
3849 "Unexpected use of __kmpc_target_init or __kmpc_target_deinit!");
3851 "Multiple uses of __kmpc_target_init or __kmpc_target_deinit!");
3857 StoreCallBase(U, InitRFI, KernelInitCB);
3861 DeinitRFI.foreachUse(
3863 StoreCallBase(U, DeinitRFI, KernelDeinitCB);
3869 if (!KernelInitCB || !KernelDeinitCB)
3873 ReachingKernelEntries.insert(Fn);
3874 IsKernelEntry =
true;
3882 KernelConfigurationSimplifyCB =
3884 bool &UsedAssumedInformation) -> std::optional<Constant *> {
3885 if (!isAtFixpoint()) {
3888 UsedAssumedInformation =
true;
3894 A.registerGlobalVariableSimplificationCallback(
3895 *KernelEnvGV, KernelConfigurationSimplifyCB);
3898 bool CanChangeToSPMD = OMPInfoCache.runtimeFnsAvailable(
3899 {OMPRTL___kmpc_get_hardware_thread_id_in_block,
3900 OMPRTL___kmpc_barrier_simple_spmd});
3904 KernelInfo::getExecModeFromKernelEnvironment(KernelEnvC);
3909 SPMDCompatibilityTracker.indicateOptimisticFixpoint();
3913 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
3915 setExecModeOfKernelEnvironment(AssumedExecModeC);
3922 setMinThreadsOfKernelEnvironment(ConstantInt::get(Int32Ty, MinThreads));
3924 setMaxThreadsOfKernelEnvironment(ConstantInt::get(Int32Ty,
MaxThreads));
3925 auto [MinTeams, MaxTeams] =
3928 setMinTeamsOfKernelEnvironment(ConstantInt::get(Int32Ty, MinTeams));
3930 setMaxTeamsOfKernelEnvironment(ConstantInt::get(Int32Ty, MaxTeams));
3933 KernelInfo::getMayUseNestedParallelismFromKernelEnvironment(KernelEnvC);
3934 ConstantInt *AssumedMayUseNestedParallelismC = ConstantInt::get(
3936 setMayUseNestedParallelismOfKernelEnvironment(
3937 AssumedMayUseNestedParallelismC);
3941 KernelInfo::getUseGenericStateMachineFromKernelEnvironment(
3944 ConstantInt::get(UseGenericStateMachineC->
getIntegerType(),
false);
3945 setUseGenericStateMachineOfKernelEnvironment(
3946 AssumedUseGenericStateMachineC);
3952 if (!OMPInfoCache.RFIs[RFKind].Declaration)
3954 A.registerVirtualUseCallback(*OMPInfoCache.RFIs[RFKind].Declaration, CB);
3958 auto AddDependence = [](
Attributor &
A,
const AAKernelInfo *KI,
3974 if (SPMDCompatibilityTracker.isValidState())
3975 return AddDependence(
A,
this, QueryingAA);
3977 if (!ReachedKnownParallelRegions.isValidState())
3978 return AddDependence(
A,
this, QueryingAA);
3984 RegisterVirtualUse(OMPRTL___kmpc_get_max_team_threads,
3985 CustomStateMachineUseCB);
3986 RegisterVirtualUse(OMPRTL___kmpc_barrier_simple_generic,
3987 CustomStateMachineUseCB);
3988 RegisterVirtualUse(OMPRTL___kmpc_kernel_parallel,
3989 CustomStateMachineUseCB);
3990 RegisterVirtualUse(OMPRTL___kmpc_kernel_end_parallel,
3991 CustomStateMachineUseCB);
3995 if (SPMDCompatibilityTracker.isAtFixpoint())
4002 if (!SPMDCompatibilityTracker.isValidState())
4003 return AddDependence(
A,
this, QueryingAA);
4006 RegisterVirtualUse(OMPRTL___kmpc_get_hardware_thread_id_in_block,
4015 if (!SPMDCompatibilityTracker.isValidState())
4016 return AddDependence(
A,
this, QueryingAA);
4017 if (SPMDCompatibilityTracker.empty())
4018 return AddDependence(
A,
this, QueryingAA);
4019 if (!mayContainParallelRegion())
4020 return AddDependence(
A,
this, QueryingAA);
4023 RegisterVirtualUse(OMPRTL___kmpc_barrier_simple_spmd, SPMDBarrierUseCB);
4027 static std::string sanitizeForGlobalName(std::string S) {
4031 return !((C >=
'a' && C <=
'z') || (C >=
'A' && C <=
'Z') ||
4032 (C >=
'0' && C <=
'9') || C ==
'_');
4043 if (!KernelInitCB || !KernelDeinitCB)
4044 return ChangeStatus::UNCHANGED;
4048 bool HasBuiltStateMachine =
true;
4049 if (!changeToSPMDMode(
A,
Changed)) {
4051 HasBuiltStateMachine = buildCustomStateMachine(
A,
Changed);
4053 HasBuiltStateMachine =
false;
4057 ConstantStruct *ExistingKernelEnvC =
4059 ConstantInt *OldUseGenericStateMachineVal =
4060 KernelInfo::getUseGenericStateMachineFromKernelEnvironment(
4061 ExistingKernelEnvC);
4062 if (!HasBuiltStateMachine)
4063 setUseGenericStateMachineOfKernelEnvironment(
4064 OldUseGenericStateMachineVal);
4067 GlobalVariable *KernelEnvGV =
4071 Changed = ChangeStatus::CHANGED;
4077 void insertInstructionGuardsHelper(Attributor &
A) {
4078 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
4080 auto CreateGuardedRegion = [&](
Instruction *RegionStartI,
4082 LoopInfo *LI =
nullptr;
4083 DominatorTree *DT =
nullptr;
4084 MemorySSAUpdater *MSU =
nullptr;
4114 DT, LI, MSU,
"region.guarded.end");
4117 MSU,
"region.barrier");
4120 DT, LI, MSU,
"region.exit");
4122 SplitBlock(ParentBB, RegionStartI, DT, LI, MSU,
"region.guarded");
4125 "Expected a different CFG");
4128 ParentBB, ParentBB->
getTerminator(), DT, LI, MSU,
"region.check.tid");
4131 A.registerManifestAddedBasicBlock(*RegionEndBB);
4132 A.registerManifestAddedBasicBlock(*RegionBarrierBB);
4133 A.registerManifestAddedBasicBlock(*RegionExitBB);
4134 A.registerManifestAddedBasicBlock(*RegionStartBB);
4135 A.registerManifestAddedBasicBlock(*RegionCheckTidBB);
4137 bool HasBroadcastValues =
false;
4140 for (Instruction &
I : *RegionStartBB) {
4142 for (Use &U :
I.uses()) {
4148 if (OutsideUses.
empty())
4151 HasBroadcastValues =
true;
4155 auto *SharedMem =
new GlobalVariable(
4156 M,
I.getType(),
false,
4158 sanitizeForGlobalName(
4159 (
I.getName() +
".guarded.output.alloc").str()),
4161 static_cast<unsigned>(AddressSpace::Shared));
4164 new StoreInst(&
I, SharedMem,
4167 LoadInst *LoadI =
new LoadInst(
4168 I.getType(), SharedMem,
I.getName() +
".guarded.output.load",
4172 for (Use *U : OutsideUses)
4173 A.changeUseAfterManifest(*U, *LoadI);
4176 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
4181 OpenMPIRBuilder::LocationDescription Loc(
4182 InsertPointTy(ParentBB, ParentBB->
end()),
DL);
4184 uint32_t SrcLocStrSize;
4193 OpenMPIRBuilder::LocationDescription LocRegionCheckTid(
4194 InsertPointTy(RegionCheckTidBB, RegionCheckTidBB->
end()),
DL);
4196 FunctionCallee HardwareTidFn =
4198 M, OMPRTL___kmpc_get_hardware_thread_id_in_block);
4202 OMPInfoCache.setCallingConvention(HardwareTidFn, Tid);
4204 OMPInfoCache.OMPBuilder.
Builder
4205 .
CreateCondBr(TidCheck, RegionStartBB, RegionBarrierBB)
4210 FunctionCallee BarrierFn =
4212 M, OMPRTL___kmpc_barrier_simple_spmd);
4214 {InsertPointTy(RegionBarrierBB,
4219 OMPInfoCache.setCallingConvention(BarrierFn, Barrier);
4222 if (HasBroadcastValues) {
4227 OMPInfoCache.setCallingConvention(BarrierFn, Barrier);
4231 auto &AllocSharedRFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
4232 SmallPtrSet<BasicBlock *, 8> Visited;
4233 for (Instruction *GuardedI : SPMDCompatibilityTracker) {
4235 if (!Visited.
insert(BB).second)
4241 while (++IP != IPEnd) {
4242 if (!IP->mayHaveSideEffects() && !IP->mayReadFromMemory())
4245 if (OpenMPOpt::getCallIfRegularCall(*
I, &AllocSharedRFI))
4247 if (!
I->user_empty() || !SPMDCompatibilityTracker.contains(
I)) {
4248 LastEffect =
nullptr;
4255 for (
auto &Reorder : Reorders)
4256 Reorder.first->moveBefore(Reorder.second->getIterator());
4261 for (Instruction *GuardedI : SPMDCompatibilityTracker) {
4263 auto *CalleeAA =
A.lookupAAFor<AAKernelInfo>(
4266 assert(CalleeAA !=
nullptr &&
"Expected Callee AAKernelInfo");
4269 if (CalleeAAFunction.getGuardedInstructions().contains(GuardedI))
4272 Instruction *GuardedRegionStart =
nullptr, *GuardedRegionEnd =
nullptr;
4273 for (Instruction &
I : *BB) {
4276 if (SPMDCompatibilityTracker.contains(&
I)) {
4277 CalleeAAFunction.getGuardedInstructions().insert(&
I);
4278 if (GuardedRegionStart)
4279 GuardedRegionEnd = &
I;
4281 GuardedRegionStart = GuardedRegionEnd = &
I;
4288 if (GuardedRegionStart) {
4290 std::make_pair(GuardedRegionStart, GuardedRegionEnd));
4291 GuardedRegionStart =
nullptr;
4292 GuardedRegionEnd =
nullptr;
4297 for (
auto &GR : GuardedRegions)
4298 CreateGuardedRegion(GR.first, GR.second);
4301 void forceSingleThreadPerWorkgroupHelper(Attributor &
A) {
4310 auto &Ctx = getAnchorValue().getContext();
4317 KernelInitCB->
getNextNode(),
"main.thread.user_code");
4322 A.registerManifestAddedBasicBlock(*InitBB);
4323 A.registerManifestAddedBasicBlock(*UserCodeBB);
4324 A.registerManifestAddedBasicBlock(*ReturnBB);
4333 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
4334 FunctionCallee ThreadIdInBlockFn =
4336 M, OMPRTL___kmpc_get_hardware_thread_id_in_block);
4339 CallInst *ThreadIdInBlock =
4341 OMPInfoCache.setCallingConvention(ThreadIdInBlockFn, ThreadIdInBlock);
4347 ConstantInt::get(ThreadIdInBlock->
getType(), 0),
4348 "thread.is_main", InitBB);
4354 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
4356 if (!SPMDCompatibilityTracker.isAssumed()) {
4357 for (Instruction *NonCompatibleI : SPMDCompatibilityTracker) {
4358 if (!NonCompatibleI)
4363 if (OMPInfoCache.RTLFunctions.contains(CB->getCalledFunction()))
4366 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
4367 ORA <<
"Value has potential side effects preventing SPMD-mode "
4370 ORA <<
". Add `[[omp::assume(\"ompx_spmd_amenable\")]]` to "
4371 "the called function to override";
4375 A.emitRemark<OptimizationRemarkAnalysis>(NonCompatibleI,
"OMP121",
4379 << *NonCompatibleI <<
"\n");
4391 Kernel = CB->getCaller();
4396 ConstantStruct *ExistingKernelEnvC =
4399 KernelInfo::getExecModeFromKernelEnvironment(ExistingKernelEnvC);
4405 Changed = ChangeStatus::CHANGED;
4409 if (mayContainParallelRegion())
4410 insertInstructionGuardsHelper(
A);
4412 forceSingleThreadPerWorkgroupHelper(
A);
4417 "Initially non-SPMD kernel has SPMD exec mode!");
4418 setExecModeOfKernelEnvironment(
4422 ++NumOpenMPTargetRegionKernelsSPMD;
4426 OMPInfoCache.SPMDizedKernels.insert(
Kernel);
4428 auto Remark = [&](OptimizationRemark
OR) {
4429 return OR <<
"Transformed generic-mode kernel to SPMD-mode.";
4431 A.emitRemark<OptimizationRemark>(KernelInitCB,
"OMP120",
Remark);
4441 if (!ReachedKnownParallelRegions.isValidState())
4444 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
4445 if (!OMPInfoCache.runtimeFnsAvailable({OMPRTL___kmpc_get_max_team_threads,
4446 OMPRTL___kmpc_barrier_simple_generic,
4447 OMPRTL___kmpc_kernel_parallel,
4448 OMPRTL___kmpc_kernel_end_parallel}))
4451 ConstantStruct *ExistingKernelEnvC =
4458 ConstantInt *UseStateMachineC =
4459 KernelInfo::getUseGenericStateMachineFromKernelEnvironment(
4460 ExistingKernelEnvC);
4461 ConstantInt *ModeC =
4462 KernelInfo::getExecModeFromKernelEnvironment(ExistingKernelEnvC);
4467 if (UseStateMachineC->
isZero() ||
4471 Changed = ChangeStatus::CHANGED;
4474 setUseGenericStateMachineOfKernelEnvironment(
4481 if (!mayContainParallelRegion()) {
4482 ++NumOpenMPTargetRegionKernelsWithoutStateMachine;
4484 auto Remark = [&](OptimizationRemark
OR) {
4485 return OR <<
"Removing unused state machine from generic-mode kernel.";
4487 A.emitRemark<OptimizationRemark>(KernelInitCB,
"OMP130",
Remark);
4493 if (ReachedUnknownParallelRegions.empty()) {
4494 ++NumOpenMPTargetRegionKernelsCustomStateMachineWithoutFallback;
4496 auto Remark = [&](OptimizationRemark
OR) {
4497 return OR <<
"Rewriting generic-mode kernel with a customized state "
4500 A.emitRemark<OptimizationRemark>(KernelInitCB,
"OMP131",
Remark);
4502 ++NumOpenMPTargetRegionKernelsCustomStateMachineWithFallback;
4504 auto Remark = [&](OptimizationRemarkAnalysis
OR) {
4505 return OR <<
"Generic-mode kernel is executed with a customized state "
4506 "machine that requires a fallback.";
4508 A.emitRemark<OptimizationRemarkAnalysis>(KernelInitCB,
"OMP132",
Remark);
4511 for (CallBase *UnknownParallelRegionCB : ReachedUnknownParallelRegions) {
4512 if (!UnknownParallelRegionCB)
4514 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
4515 return ORA <<
"Call may contain unknown parallel regions. Use "
4516 <<
"`[[omp::assume(\"omp_no_parallelism\")]]` to "
4519 A.emitRemark<OptimizationRemarkAnalysis>(UnknownParallelRegionCB,
4552 auto &Ctx = getAnchorValue().getContext();
4556 BasicBlock *InitBB = KernelInitCB->getParent();
4558 KernelInitCB->getNextNode(),
"thread.user_code.check");
4562 Ctx,
"worker_state_machine.begin",
Kernel, UserCodeEntryBB);
4564 Ctx,
"worker_state_machine.finished",
Kernel, UserCodeEntryBB);
4566 Ctx,
"worker_state_machine.is_active.check",
Kernel, UserCodeEntryBB);
4569 Kernel, UserCodeEntryBB);
4572 Kernel, UserCodeEntryBB);
4574 Ctx,
"worker_state_machine.done.barrier",
Kernel, UserCodeEntryBB);
4575 A.registerManifestAddedBasicBlock(*InitBB);
4576 A.registerManifestAddedBasicBlock(*UserCodeEntryBB);
4577 A.registerManifestAddedBasicBlock(*IsWorkerCheckBB);
4578 A.registerManifestAddedBasicBlock(*StateMachineBeginBB);
4579 A.registerManifestAddedBasicBlock(*StateMachineFinishedBB);
4580 A.registerManifestAddedBasicBlock(*StateMachineIsActiveCheckBB);
4581 A.registerManifestAddedBasicBlock(*StateMachineIfCascadeCurrentBB);
4582 A.registerManifestAddedBasicBlock(*StateMachineEndParallelBB);
4583 A.registerManifestAddedBasicBlock(*StateMachineDoneBarrierBB);
4585 const DebugLoc &DLoc = KernelInitCB->getDebugLoc();
4591 ConstantInt::getAllOnesValue(KernelInitCB->getType()),
4592 "thread.is_worker", InitBB);
4601 FunctionCallee MaxTeamThreadsFn =
4603 M, OMPRTL___kmpc_get_max_team_threads);
4604 Constant *IsSPMDArg = ConstantInt::get(OMPInfoCache.OMPBuilder.Int32, 0);
4606 MaxTeamThreadsFn, {IsSPMDArg},
"max_team_threads", IsWorkerCheckBB);
4607 OMPInfoCache.setCallingConvention(MaxTeamThreadsFn, MaxTeamThreads);
4611 "thread.is_main_or_worker", IsWorkerCheckBB);
4614 StateMachineFinishedBB, IsWorkerCheckBB);
4617 const DataLayout &
DL =
M.getDataLayout();
4618 Type *VoidPtrTy = PointerType::getUnqual(Ctx);
4620 new AllocaInst(VoidPtrTy,
DL.getAllocaAddrSpace(),
nullptr,
4625 OpenMPIRBuilder::LocationDescription(
4626 IRBuilder<>::InsertPoint(StateMachineBeginBB,
4627 StateMachineBeginBB->
end()),
4630 Value *Ident = KernelInfo::getIdentFromKernelEnvironment(KernelEnvC);
4631 Value *GTid = KernelInitCB;
4633 FunctionCallee BarrierFn =
4635 M, OMPRTL___kmpc_barrier_simple_generic);
4638 OMPInfoCache.setCallingConvention(BarrierFn, Barrier);
4642 (
unsigned int)AddressSpace::Generic) {
4643 WorkFnAI =
new AddrSpaceCastInst(
4644 WorkFnAI, PointerType::get(Ctx, (
unsigned int)AddressSpace::Generic),
4645 WorkFnAI->
getName() +
".generic", StateMachineBeginBB);
4649 FunctionCallee KernelParallelFn =
4651 M, OMPRTL___kmpc_kernel_parallel);
4653 KernelParallelFn, {WorkFnAI},
"worker.is_active", StateMachineBeginBB);
4654 OMPInfoCache.setCallingConvention(KernelParallelFn, IsActiveWorker);
4656 Instruction *WorkFn =
new LoadInst(VoidPtrTy, WorkFnAI,
"worker.work_fn",
4657 StateMachineBeginBB);
4660 FunctionType *ParallelRegionFnTy = FunctionType::get(
4661 Type::getVoidTy(Ctx), {Type::getInt16Ty(Ctx), Type::getInt32Ty(Ctx)},
4667 StateMachineBeginBB);
4668 IsDone->setDebugLoc(DLoc);
4670 StateMachineIsActiveCheckBB, StateMachineBeginBB)
4674 StateMachineDoneBarrierBB, StateMachineIsActiveCheckBB)
4680 const unsigned int WrapperFunctionArgNo = 6;
4685 for (
int I = 0,
E = ReachedKnownParallelRegions.size();
I <
E; ++
I) {
4686 auto *CB = ReachedKnownParallelRegions[
I];
4688 CB->getArgOperand(WrapperFunctionArgNo)->stripPointerCasts());
4690 Ctx,
"worker_state_machine.parallel_region.execute",
Kernel,
4691 StateMachineEndParallelBB);
4693 ->setDebugLoc(DLoc);
4699 Kernel, StateMachineEndParallelBB);
4700 A.registerManifestAddedBasicBlock(*PRExecuteBB);
4701 A.registerManifestAddedBasicBlock(*PRNextBB);
4706 if (
I + 1 <
E || !ReachedUnknownParallelRegions.empty()) {
4709 "worker.check_parallel_region", StateMachineIfCascadeCurrentBB);
4717 StateMachineIfCascadeCurrentBB)
4719 StateMachineIfCascadeCurrentBB = PRNextBB;
4725 if (!ReachedUnknownParallelRegions.empty()) {
4726 StateMachineIfCascadeCurrentBB->
setName(
4727 "worker_state_machine.parallel_region.fallback.execute");
4729 StateMachineIfCascadeCurrentBB)
4730 ->setDebugLoc(DLoc);
4733 StateMachineIfCascadeCurrentBB)
4736 FunctionCallee EndParallelFn =
4738 M, OMPRTL___kmpc_kernel_end_parallel);
4739 CallInst *EndParallel =
4741 OMPInfoCache.setCallingConvention(EndParallelFn, EndParallel);
4747 ->setDebugLoc(DLoc);
4757 KernelInfoState StateBefore = getState();
4763 struct UpdateKernelEnvCRAII {
4764 AAKernelInfoFunction &AA;
4766 UpdateKernelEnvCRAII(AAKernelInfoFunction &AA) : AA(AA) {}
4768 ~UpdateKernelEnvCRAII() {
4772 ConstantStruct *ExistingKernelEnvC =
4775 if (!AA.isValidState()) {
4776 AA.KernelEnvC = ExistingKernelEnvC;
4780 if (!AA.ReachedKnownParallelRegions.isValidState())
4781 AA.setUseGenericStateMachineOfKernelEnvironment(
4782 KernelInfo::getUseGenericStateMachineFromKernelEnvironment(
4783 ExistingKernelEnvC));
4785 if (!AA.SPMDCompatibilityTracker.isValidState())
4786 AA.setExecModeOfKernelEnvironment(
4787 KernelInfo::getExecModeFromKernelEnvironment(ExistingKernelEnvC));
4789 ConstantInt *MayUseNestedParallelismC =
4790 KernelInfo::getMayUseNestedParallelismFromKernelEnvironment(
4792 ConstantInt *NewMayUseNestedParallelismC = ConstantInt::get(
4793 MayUseNestedParallelismC->
getIntegerType(), AA.NestedParallelism);
4794 AA.setMayUseNestedParallelismOfKernelEnvironment(
4795 NewMayUseNestedParallelismC);
4805 if (!
I.mayWriteToMemory())
4808 const auto *UnderlyingObjsAA =
A.getAAFor<AAUnderlyingObjects>(
4810 DepClassTy::OPTIONAL);
4811 auto *
HS =
A.getAAFor<AAHeapToStack>(
4813 DepClassTy::OPTIONAL);
4814 if (UnderlyingObjsAA &&
4815 UnderlyingObjsAA->forallUnderlyingObjects([&](
Value &Obj) {
4816 if (AA::isAssumedThreadLocalObject(A, Obj, *this))
4820 auto *CB = dyn_cast<CallBase>(&Obj);
4821 return CB && HS && HS->isAssumedHeapToStack(*CB);
4827 SPMDCompatibilityTracker.insert(&
I);
4831 bool UsedAssumedInformationInCheckRWInst =
false;
4832 if (!SPMDCompatibilityTracker.isAtFixpoint())
4833 if (!
A.checkForAllReadWriteInstructions(
4834 CheckRWInst, *
this, UsedAssumedInformationInCheckRWInst))
4835 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
4837 bool UsedAssumedInformationFromReachingKernels =
false;
4838 if (!IsKernelEntry) {
4839 updateParallelLevels(
A);
4841 bool AllReachingKernelsKnown =
true;
4842 updateReachingKernelEntries(
A, AllReachingKernelsKnown);
4843 UsedAssumedInformationFromReachingKernels = !AllReachingKernelsKnown;
4845 if (!SPMDCompatibilityTracker.empty()) {
4846 if (!ParallelLevels.isValidState())
4847 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
4848 else if (!ReachingKernelEntries.isValidState())
4849 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
4855 for (
auto *
Kernel : ReachingKernelEntries) {
4856 auto *CBAA =
A.getAAFor<AAKernelInfo>(
4858 if (CBAA && CBAA->SPMDCompatibilityTracker.isValidState() &&
4859 CBAA->SPMDCompatibilityTracker.isAssumed())
4863 if (!CBAA || !CBAA->SPMDCompatibilityTracker.isAtFixpoint())
4864 UsedAssumedInformationFromReachingKernels =
true;
4866 if (SPMD != 0 &&
Generic != 0)
4867 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
4873 bool AllParallelRegionStatesWereFixed =
true;
4874 bool AllSPMDStatesWereFixed =
true;
4881 if (
Function *Callback = OMPInformationCache::getAnalyzableCallback(CB)) {
4883 <<
Callback->getName() <<
" of " << CB <<
"\n");
4884 if (
auto *CallbackAA =
A.getAAFor<AAKernelInfo>(
4886 getState() ^= CallbackAA->getState();
4887 AllSPMDStatesWereFixed &=
4888 CallbackAA->SPMDCompatibilityTracker.isAtFixpoint();
4889 AllParallelRegionStatesWereFixed &=
4890 CallbackAA->ReachedKnownParallelRegions.isAtFixpoint();
4891 AllParallelRegionStatesWereFixed &=
4892 CallbackAA->ReachedUnknownParallelRegions.isAtFixpoint();
4895 auto *CBAA =
A.getAAFor<AAKernelInfo>(
4899 getState() ^= CBAA->getState();
4900 AllSPMDStatesWereFixed &= CBAA->SPMDCompatibilityTracker.isAtFixpoint();
4901 AllParallelRegionStatesWereFixed &=
4902 CBAA->ReachedKnownParallelRegions.isAtFixpoint();
4903 AllParallelRegionStatesWereFixed &=
4904 CBAA->ReachedUnknownParallelRegions.isAtFixpoint();
4908 bool UsedAssumedInformationInCheckCallInst =
false;
4909 if (!
A.checkForAllCallLikeInstructions(
4910 CheckCallInst, *
this, UsedAssumedInformationInCheckCallInst)) {
4912 <<
"Failed to visit all call-like instructions!\n";);
4913 return indicatePessimisticFixpoint();
4918 if (!UsedAssumedInformationInCheckCallInst &&
4919 AllParallelRegionStatesWereFixed) {
4920 ReachedKnownParallelRegions.indicateOptimisticFixpoint();
4921 ReachedUnknownParallelRegions.indicateOptimisticFixpoint();
4926 if (!UsedAssumedInformationInCheckRWInst &&
4927 !UsedAssumedInformationInCheckCallInst &&
4928 !UsedAssumedInformationFromReachingKernels && AllSPMDStatesWereFixed)
4929 SPMDCompatibilityTracker.indicateOptimisticFixpoint();
4931 return StateBefore == getState() ? ChangeStatus::UNCHANGED
4932 : ChangeStatus::CHANGED;
4937 void updateReachingKernelEntries(Attributor &
A,
4938 bool &AllReachingKernelsKnown) {
4939 auto PredCallSite = [&](AbstractCallSite ACS) {
4942 assert(Caller &&
"Caller is nullptr");
4944 auto *CAA =
A.getOrCreateAAFor<AAKernelInfo>(
4946 if (CAA && CAA->ReachingKernelEntries.isValidState()) {
4947 ReachingKernelEntries ^= CAA->ReachingKernelEntries;
4953 ReachingKernelEntries.indicatePessimisticFixpoint();
4958 if (!
A.checkForAllCallSites(PredCallSite, *
this,
4960 AllReachingKernelsKnown))
4961 ReachingKernelEntries.indicatePessimisticFixpoint();
4965 void updateParallelLevels(Attributor &
A) {
4966 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
4967 OMPInformationCache::RuntimeFunctionInfo &Parallel60RFI =
4968 OMPInfoCache.RFIs[OMPRTL___kmpc_parallel_60];
4970 auto PredCallSite = [&](AbstractCallSite ACS) {
4973 assert(Caller &&
"Caller is nullptr");
4977 if (CAA && CAA->ParallelLevels.isValidState()) {
4983 if (Caller == Parallel60RFI.Declaration) {
4984 ParallelLevels.indicatePessimisticFixpoint();
4988 ParallelLevels ^= CAA->ParallelLevels;
4995 ParallelLevels.indicatePessimisticFixpoint();
5000 bool AllCallSitesKnown =
true;
5001 if (!
A.checkForAllCallSites(PredCallSite, *
this,
5004 ParallelLevels.indicatePessimisticFixpoint();
5011struct AAKernelInfoCallSite : AAKernelInfo {
5012 AAKernelInfoCallSite(
const IRPosition &IRP, Attributor &
A)
5013 : AAKernelInfo(IRP,
A) {}
5017 AAKernelInfo::initialize(
A);
5020 auto *AssumptionAA =
A.getAAFor<AAAssumptionInfo>(
5024 if (AssumptionAA && AssumptionAA->hasAssumption(
"ompx_spmd_amenable")) {
5025 indicateOptimisticFixpoint();
5033 indicateOptimisticFixpoint();
5042 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
5043 const auto &It = OMPInfoCache.RuntimeFunctionIDMap.find(Callee);
5044 if (It == OMPInfoCache.RuntimeFunctionIDMap.end()) {
5046 if (!Callee || !
A.isFunctionIPOAmendable(*Callee)) {
5050 if (!AssumptionAA ||
5051 !(AssumptionAA->hasAssumption(
"omp_no_openmp") ||
5052 AssumptionAA->hasAssumption(
"omp_no_parallelism")))
5053 ReachedUnknownParallelRegions.insert(&CB);
5057 if (!SPMDCompatibilityTracker.isAtFixpoint()) {
5058 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5059 SPMDCompatibilityTracker.insert(&CB);
5064 indicateOptimisticFixpoint();
5073 if (NumCallees > 1 && !
Callee->hasMetadata(LLVMContext::MD_callback)) {
5074 indicatePessimisticFixpoint();
5081 case OMPRTL___kmpc_is_spmd_exec_mode:
5082 case OMPRTL___kmpc_distribute_static_fini:
5083 case OMPRTL___kmpc_for_static_fini:
5084 case OMPRTL___kmpc_global_thread_num:
5085 case OMPRTL___kmpc_get_hardware_num_threads_in_block:
5086 case OMPRTL___kmpc_get_hardware_num_blocks:
5087 case OMPRTL___kmpc_single:
5088 case OMPRTL___kmpc_end_single:
5089 case OMPRTL___kmpc_master:
5090 case OMPRTL___kmpc_end_master:
5091 case OMPRTL___kmpc_barrier:
5092 case OMPRTL___kmpc_nvptx_parallel_reduce_nowait_v2:
5093 case OMPRTL___kmpc_gpu_xteam_reduce_nowait:
5094 case OMPRTL___kmpc_error:
5095 case OMPRTL___kmpc_flush:
5096 case OMPRTL___kmpc_get_hardware_thread_id_in_block:
5097 case OMPRTL___kmpc_get_warp_size:
5098 case OMPRTL_omp_get_thread_num:
5099 case OMPRTL_omp_get_num_threads:
5100 case OMPRTL_omp_get_max_threads:
5101 case OMPRTL_omp_in_parallel:
5102 case OMPRTL_omp_get_dynamic:
5103 case OMPRTL_omp_get_cancellation:
5104 case OMPRTL_omp_get_nested:
5105 case OMPRTL_omp_get_schedule:
5106 case OMPRTL_omp_get_thread_limit:
5107 case OMPRTL_omp_get_supported_active_levels:
5108 case OMPRTL_omp_get_max_active_levels:
5109 case OMPRTL_omp_get_level:
5110 case OMPRTL_omp_get_ancestor_thread_num:
5111 case OMPRTL_omp_get_team_size:
5112 case OMPRTL_omp_get_active_level:
5113 case OMPRTL_omp_in_final:
5114 case OMPRTL_omp_get_proc_bind:
5115 case OMPRTL_omp_get_num_places:
5116 case OMPRTL_omp_get_num_procs:
5117 case OMPRTL_omp_get_place_proc_ids:
5118 case OMPRTL_omp_get_place_num:
5119 case OMPRTL_omp_get_partition_num_places:
5120 case OMPRTL_omp_get_partition_place_nums:
5121 case OMPRTL_omp_get_wtime:
5123 case OMPRTL___kmpc_distribute_static_init_4:
5124 case OMPRTL___kmpc_distribute_static_init_4u:
5125 case OMPRTL___kmpc_distribute_static_init_8:
5126 case OMPRTL___kmpc_distribute_static_init_8u:
5127 case OMPRTL___kmpc_for_static_init_4:
5128 case OMPRTL___kmpc_for_static_init_4u:
5129 case OMPRTL___kmpc_for_static_init_8:
5130 case OMPRTL___kmpc_for_static_init_8u: {
5132 unsigned ScheduleArgOpNo = 2;
5133 auto *ScheduleTypeCI =
5135 unsigned ScheduleTypeVal =
5136 ScheduleTypeCI ? ScheduleTypeCI->getZExtValue() : 0;
5138 case OMPScheduleType::UnorderedStatic:
5139 case OMPScheduleType::UnorderedStaticChunked:
5140 case OMPScheduleType::OrderedDistribute:
5141 case OMPScheduleType::OrderedDistributeChunked:
5144 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5145 SPMDCompatibilityTracker.insert(&CB);
5149 case OMPRTL___kmpc_target_init:
5152 case OMPRTL___kmpc_target_deinit:
5153 KernelDeinitCB = &CB;
5155 case OMPRTL___kmpc_parallel_60:
5156 if (!handleParallel60(
A, CB))
5157 indicatePessimisticFixpoint();
5159 case OMPRTL___kmpc_omp_task:
5161 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5162 SPMDCompatibilityTracker.insert(&CB);
5163 ReachedUnknownParallelRegions.insert(&CB);
5165 case OMPRTL___kmpc_alloc_shared:
5166 case OMPRTL___kmpc_free_shared:
5174 case OMPRTL___kmpc_distribute_static_loop_4:
5175 case OMPRTL___kmpc_distribute_static_loop_4u:
5176 case OMPRTL___kmpc_distribute_static_loop_8:
5177 case OMPRTL___kmpc_distribute_static_loop_8u:
5185 if (!OMPInformationCache::getAnalyzableCallback(CB))
5186 ReachedUnknownParallelRegions.insert(&CB);
5187 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5188 SPMDCompatibilityTracker.insert(&CB);
5190 case OMPRTL___kmpc_distribute_for_static_loop_4:
5191 case OMPRTL___kmpc_distribute_for_static_loop_4u:
5192 case OMPRTL___kmpc_distribute_for_static_loop_8:
5193 case OMPRTL___kmpc_distribute_for_static_loop_8u:
5194 case OMPRTL___kmpc_for_static_loop_4:
5195 case OMPRTL___kmpc_for_static_loop_4u:
5196 case OMPRTL___kmpc_for_static_loop_8:
5197 case OMPRTL___kmpc_for_static_loop_8u:
5206 if (!OMPInformationCache::getAnalyzableCallback(CB))
5207 ReachedUnknownParallelRegions.insert(&CB);
5208 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5209 SPMDCompatibilityTracker.insert(&CB);
5214 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5215 SPMDCompatibilityTracker.insert(&CB);
5221 indicateOptimisticFixpoint();
5225 A.getAAFor<AACallEdges>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
5226 if (!AACE || !AACE->getState().isValidState() || AACE->hasUnknownCallee()) {
5227 CheckCallee(getAssociatedFunction(), 1);
5230 const auto &OptimisticEdges = AACE->getOptimisticEdges();
5231 for (
auto *Callee : OptimisticEdges) {
5232 CheckCallee(Callee, OptimisticEdges.size());
5243 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
5244 KernelInfoState StateBefore = getState();
5246 auto CheckCallee = [&](
Function *
F,
int NumCallees) {
5247 const auto &It = OMPInfoCache.RuntimeFunctionIDMap.find(
F);
5251 if (It == OMPInfoCache.RuntimeFunctionIDMap.end()) {
5254 A.getAAFor<AAKernelInfo>(*
this, FnPos, DepClassTy::REQUIRED);
5256 return indicatePessimisticFixpoint();
5257 if (getState() == FnAA->getState())
5258 return ChangeStatus::UNCHANGED;
5259 getState() = FnAA->getState();
5260 return ChangeStatus::CHANGED;
5264 if (NumCallees > 1 && !
F->hasMetadata(LLVMContext::MD_callback))
5265 return indicatePessimisticFixpoint();
5268 if (It->getSecond() == OMPRTL___kmpc_parallel_60) {
5269 if (!handleParallel60(
A, CB))
5270 return indicatePessimisticFixpoint();
5271 return StateBefore == getState() ? ChangeStatus::UNCHANGED
5272 : ChangeStatus::CHANGED;
5278 (It->getSecond() == OMPRTL___kmpc_alloc_shared ||
5279 It->getSecond() == OMPRTL___kmpc_free_shared) &&
5280 "Expected a __kmpc_alloc_shared or __kmpc_free_shared runtime call");
5282 auto *HeapToStackAA =
A.getAAFor<AAHeapToStack>(
5284 auto *HeapToSharedAA =
A.getAAFor<AAHeapToShared>(
5292 case OMPRTL___kmpc_alloc_shared:
5293 if ((!HeapToStackAA || !HeapToStackAA->isAssumedHeapToStack(CB)) &&
5294 (!HeapToSharedAA || !HeapToSharedAA->isAssumedHeapToShared(CB)))
5295 SPMDCompatibilityTracker.insert(&CB);
5297 case OMPRTL___kmpc_free_shared:
5298 if ((!HeapToStackAA ||
5299 !HeapToStackAA->isAssumedHeapToStackRemovedFree(CB)) &&
5301 !HeapToSharedAA->isAssumedHeapToSharedRemovedFree(CB)))
5302 SPMDCompatibilityTracker.insert(&CB);
5305 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5306 SPMDCompatibilityTracker.insert(&CB);
5308 return ChangeStatus::CHANGED;
5312 A.getAAFor<AACallEdges>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
5313 if (!AACE || !AACE->getState().isValidState() || AACE->hasUnknownCallee()) {
5314 if (
Function *
F = getAssociatedFunction())
5317 const auto &OptimisticEdges = AACE->getOptimisticEdges();
5318 for (
auto *Callee : OptimisticEdges) {
5319 CheckCallee(Callee, OptimisticEdges.size());
5325 return StateBefore == getState() ? ChangeStatus::UNCHANGED
5326 : ChangeStatus::CHANGED;
5331 bool handleParallel60(Attributor &
A, CallBase &CB) {
5332 const unsigned int NonWrapperFunctionArgNo = 5;
5333 const unsigned int WrapperFunctionArgNo = 6;
5334 auto ParallelRegionOpArgNo = SPMDCompatibilityTracker.isAssumed()
5335 ? NonWrapperFunctionArgNo
5336 : WrapperFunctionArgNo;
5340 if (!ParallelRegion)
5343 ReachedKnownParallelRegions.insert(&CB);
5345 auto *FnAA =
A.getAAFor<AAKernelInfo>(
5347 NestedParallelism |= !FnAA || !FnAA->getState().isValidState() ||
5348 !FnAA->ReachedKnownParallelRegions.empty() ||
5349 !FnAA->ReachedKnownParallelRegions.isValidState() ||
5350 !FnAA->ReachedUnknownParallelRegions.isValidState() ||
5351 !FnAA->ReachedUnknownParallelRegions.empty();
5356struct AAFoldRuntimeCall
5357 :
public StateWrapper<BooleanState, AbstractAttribute> {
5358 using Base = StateWrapper<BooleanState, AbstractAttribute>;
5360 AAFoldRuntimeCall(
const IRPosition &IRP, Attributor &
A) :
Base(IRP) {}
5363 void trackStatistics()
const override {}
5366 static AAFoldRuntimeCall &createForPosition(
const IRPosition &IRP,
5370 StringRef
getName()
const override {
return "AAFoldRuntimeCall"; }
5373 const char *getIdAddr()
const override {
return &ID; }
5377 static bool classof(
const AbstractAttribute *AA) {
5381 static const char ID;
5384struct AAFoldRuntimeCallCallSiteReturned : AAFoldRuntimeCall {
5385 AAFoldRuntimeCallCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5386 : AAFoldRuntimeCall(IRP,
A) {}
5389 const std::string getAsStr(Attributor *)
const override {
5390 if (!isValidState())
5393 std::string Str(
"simplified value: ");
5395 if (!SimplifiedValue)
5396 return Str + std::string(
"none");
5398 if (!*SimplifiedValue)
5399 return Str + std::string(
"nullptr");
5402 return Str + std::to_string(CI->getSExtValue());
5404 return Str + std::string(
"unknown");
5409 indicatePessimisticFixpoint();
5413 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
5414 const auto &It = OMPInfoCache.RuntimeFunctionIDMap.find(Callee);
5415 assert(It != OMPInfoCache.RuntimeFunctionIDMap.end() &&
5416 "Expected a known OpenMP runtime function");
5418 RFKind = It->getSecond();
5421 A.registerSimplificationCallback(
5423 [&](
const IRPosition &IRP,
const AbstractAttribute *AA,
5424 bool &UsedAssumedInformation) -> std::optional<Value *> {
5425 assert((isValidState() || SimplifiedValue ==
nullptr) &&
5426 "Unexpected invalid state!");
5428 if (!isAtFixpoint()) {
5429 UsedAssumedInformation =
true;
5431 A.recordDependence(*
this, *AA, DepClassTy::OPTIONAL);
5433 return SimplifiedValue;
5440 case OMPRTL___kmpc_is_spmd_exec_mode:
5443 case OMPRTL___kmpc_parallel_level:
5446 case OMPRTL___kmpc_get_hardware_num_threads_in_block:
5447 Changed =
Changed | foldKernelFnAttribute(
A,
"omp_target_thread_limit");
5449 case OMPRTL___kmpc_get_hardware_num_blocks:
5462 if (SimplifiedValue && *SimplifiedValue) {
5465 A.deleteAfterManifest(
I);
5468 auto Remark = [&](OptimizationRemark
OR) {
5470 return OR <<
"Replacing OpenMP runtime call "
5472 <<
ore::NV(
"FoldedValue",
C->getZExtValue()) <<
".";
5473 return OR <<
"Replacing OpenMP runtime call "
5478 A.emitRemark<OptimizationRemark>(CB,
"OMP180",
Remark);
5481 << **SimplifiedValue <<
"\n");
5483 Changed = ChangeStatus::CHANGED;
5490 SimplifiedValue =
nullptr;
5491 return AAFoldRuntimeCall::indicatePessimisticFixpoint();
5497 std::optional<Value *> SimplifiedValueBefore = SimplifiedValue;
5499 unsigned AssumedSPMDCount = 0, KnownSPMDCount = 0;
5500 unsigned AssumedNonSPMDCount = 0, KnownNonSPMDCount = 0;
5501 auto *CallerKernelInfoAA =
A.getAAFor<AAKernelInfo>(
5504 if (!CallerKernelInfoAA ||
5505 !CallerKernelInfoAA->ReachingKernelEntries.isValidState())
5506 return indicatePessimisticFixpoint();
5508 for (
Kernel K : CallerKernelInfoAA->ReachingKernelEntries) {
5510 DepClassTy::REQUIRED);
5512 if (!AA || !AA->isValidState()) {
5513 SimplifiedValue =
nullptr;
5514 return indicatePessimisticFixpoint();
5517 if (AA->SPMDCompatibilityTracker.isAssumed()) {
5518 if (AA->SPMDCompatibilityTracker.isAtFixpoint())
5523 if (AA->SPMDCompatibilityTracker.isAtFixpoint())
5524 ++KnownNonSPMDCount;
5526 ++AssumedNonSPMDCount;
5530 if ((AssumedSPMDCount + KnownSPMDCount) &&
5531 (AssumedNonSPMDCount + KnownNonSPMDCount))
5532 return indicatePessimisticFixpoint();
5534 auto &Ctx = getAnchorValue().getContext();
5535 if (KnownSPMDCount || AssumedSPMDCount) {
5536 assert(KnownNonSPMDCount == 0 && AssumedNonSPMDCount == 0 &&
5537 "Expected only SPMD kernels!");
5540 SimplifiedValue = ConstantInt::get(Type::getInt8Ty(Ctx),
true);
5541 }
else if (KnownNonSPMDCount || AssumedNonSPMDCount) {
5542 assert(KnownSPMDCount == 0 && AssumedSPMDCount == 0 &&
5543 "Expected only non-SPMD kernels!");
5546 SimplifiedValue = ConstantInt::get(Type::getInt8Ty(Ctx),
false);
5551 assert(!SimplifiedValue &&
"SimplifiedValue should be none");
5554 return SimplifiedValue == SimplifiedValueBefore ? ChangeStatus::UNCHANGED
5555 : ChangeStatus::CHANGED;
5560 std::optional<Value *> SimplifiedValueBefore = SimplifiedValue;
5562 auto *CallerKernelInfoAA =
A.getAAFor<AAKernelInfo>(
5565 if (!CallerKernelInfoAA ||
5566 !CallerKernelInfoAA->ParallelLevels.isValidState())
5567 return indicatePessimisticFixpoint();
5569 if (!CallerKernelInfoAA->ReachingKernelEntries.isValidState())
5570 return indicatePessimisticFixpoint();
5572 if (CallerKernelInfoAA->ReachingKernelEntries.empty()) {
5573 assert(!SimplifiedValue &&
5574 "SimplifiedValue should keep none at this point");
5575 return ChangeStatus::UNCHANGED;
5578 unsigned AssumedSPMDCount = 0, KnownSPMDCount = 0;
5579 unsigned AssumedNonSPMDCount = 0, KnownNonSPMDCount = 0;
5580 for (
Kernel K : CallerKernelInfoAA->ReachingKernelEntries) {
5582 DepClassTy::REQUIRED);
5583 if (!AA || !AA->SPMDCompatibilityTracker.isValidState())
5584 return indicatePessimisticFixpoint();
5586 if (AA->SPMDCompatibilityTracker.isAssumed()) {
5587 if (AA->SPMDCompatibilityTracker.isAtFixpoint())
5592 if (AA->SPMDCompatibilityTracker.isAtFixpoint())
5593 ++KnownNonSPMDCount;
5595 ++AssumedNonSPMDCount;
5599 if ((AssumedSPMDCount + KnownSPMDCount) &&
5600 (AssumedNonSPMDCount + KnownNonSPMDCount))
5601 return indicatePessimisticFixpoint();
5603 auto &Ctx = getAnchorValue().getContext();
5607 if (AssumedSPMDCount || KnownSPMDCount) {
5608 assert(KnownNonSPMDCount == 0 && AssumedNonSPMDCount == 0 &&
5609 "Expected only SPMD kernels!");
5610 SimplifiedValue = ConstantInt::get(Type::getInt8Ty(Ctx), 1);
5612 assert(KnownSPMDCount == 0 && AssumedSPMDCount == 0 &&
5613 "Expected only non-SPMD kernels!");
5614 SimplifiedValue = ConstantInt::get(Type::getInt8Ty(Ctx), 0);
5616 return SimplifiedValue == SimplifiedValueBefore ? ChangeStatus::UNCHANGED
5617 : ChangeStatus::CHANGED;
5620 ChangeStatus foldKernelFnAttribute(Attributor &
A, llvm::StringRef Attr) {
5622 int32_t CurrentAttrValue = -1;
5623 std::optional<Value *> SimplifiedValueBefore = SimplifiedValue;
5625 auto *CallerKernelInfoAA =
A.getAAFor<AAKernelInfo>(
5628 if (!CallerKernelInfoAA ||
5629 !CallerKernelInfoAA->ReachingKernelEntries.isValidState())
5630 return indicatePessimisticFixpoint();
5633 for (
Kernel K : CallerKernelInfoAA->ReachingKernelEntries) {
5634 int32_t NextAttrVal =
K->getFnAttributeAsParsedInteger(Attr, -1);
5636 if (NextAttrVal == -1 ||
5637 (CurrentAttrValue != -1 && CurrentAttrValue != NextAttrVal))
5638 return indicatePessimisticFixpoint();
5639 CurrentAttrValue = NextAttrVal;
5642 if (CurrentAttrValue != -1) {
5643 auto &Ctx = getAnchorValue().getContext();
5645 ConstantInt::get(Type::getInt32Ty(Ctx), CurrentAttrValue);
5647 return SimplifiedValue == SimplifiedValueBefore ? ChangeStatus::UNCHANGED
5648 : ChangeStatus::CHANGED;
5654 std::optional<Value *> SimplifiedValue;
5664 auto &RFI = OMPInfoCache.RFIs[RF];
5665 RFI.foreachUse(SCC, [&](Use &U,
Function &
F) {
5666 CallInst *CI = OpenMPOpt::getCallIfRegularCall(U, &RFI);
5669 A.getOrCreateAAFor<AAFoldRuntimeCall>(
5671 DepClassTy::NONE,
false,
5677void OpenMPOpt::registerAAs(
bool IsModulePass) {
5687 A.getOrCreateAAFor<AAKernelInfo>(
5689 DepClassTy::NONE,
false,
5693 OMPInformationCache::RuntimeFunctionInfo &InitRFI =
5694 OMPInfoCache.RFIs[OMPRTL___kmpc_target_init];
5695 InitRFI.foreachUse(SCC, CreateKernelInfoCB);
5697 registerFoldRuntimeCall(OMPRTL___kmpc_is_spmd_exec_mode);
5698 registerFoldRuntimeCall(OMPRTL___kmpc_parallel_level);
5699 registerFoldRuntimeCall(OMPRTL___kmpc_get_hardware_num_threads_in_block);
5700 registerFoldRuntimeCall(OMPRTL___kmpc_get_hardware_num_blocks);
5705 for (
int Idx = 0; Idx < OMPInfoCache.ICVs.size() - 1; ++Idx) {
5708 auto &GetterRFI = OMPInfoCache.RFIs[ICVInfo.Getter];
5711 CallInst *CI = OpenMPOpt::getCallIfRegularCall(U, &GetterRFI);
5718 A.getOrCreateAAFor<AAICVTracker>(CBPos);
5722 GetterRFI.foreachUse(SCC, CreateAA);
5731 for (
auto *
F : SCC) {
5732 if (
F->isDeclaration())
5738 if (
F->hasLocalLinkage()) {
5740 const auto *CB = dyn_cast<CallBase>(U.getUser());
5741 return CB && CB->isCallee(&U) &&
5742 A.isRunOn(const_cast<Function *>(CB->getCaller()));
5746 registerAAsForFunction(
A, *
F);
5750void OpenMPOpt::registerAAsForFunction(Attributor &
A,
const Function &
F) {
5751 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
5754 A.getOrCreateAAFor<AAExecutionDomain>(FPos);
5755 if (
F.hasFnAttribute(Attribute::Convergent))
5756 A.getOrCreateAAFor<AANonConvergent>(FPos);
5758 bool FunctionUsesSharedAlloc =
false;
5760 const OMPInformationCache::RuntimeFunctionInfo::UseVector *SharedAllocUses =
5761 OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared].getUseVector(
5763 FunctionUsesSharedAlloc = SharedAllocUses && !SharedAllocUses->
empty();
5765 bool HasHeapToStackCandidate =
false;
5766 const TargetLibraryInfo *TLI =
nullptr;
5770 bool UsedAssumedInformation =
false;
5773 A.getOrCreateAAFor<AAAddressSpace>(
5780 TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(
F);
5781 HasHeapToStackCandidate =
5785 A.getOrCreateAAFor<AAIndirectCallInfo>(
5790 A.getOrCreateAAFor<AAAddressSpace>(
5799 if (
II->getIntrinsicID() == Intrinsic::assume) {
5800 A.getOrCreateAAFor<AAPotentialValues>(
5807 if (FunctionUsesSharedAlloc)
5808 A.getOrCreateAAFor<AAHeapToShared>(FPos);
5809 if (HasHeapToStackCandidate)
5810 A.getOrCreateAAFor<AAHeapToStack>(FPos);
5813const char AAICVTracker::ID = 0;
5814const char AAKernelInfo::ID = 0;
5816const char AAHeapToShared::ID = 0;
5817const char AAFoldRuntimeCall::ID = 0;
5819AAICVTracker &AAICVTracker::createForPosition(
const IRPosition &IRP,
5821 AAICVTracker *AA =
nullptr;
5829 AA =
new (
A.Allocator) AAICVTrackerFunctionReturned(IRP,
A);
5832 AA =
new (
A.Allocator) AAICVTrackerCallSiteReturned(IRP,
A);
5835 AA =
new (
A.Allocator) AAICVTrackerCallSite(IRP,
A);
5838 AA =
new (
A.Allocator) AAICVTrackerFunction(IRP,
A);
5847 AAExecutionDomainFunction *
AA =
nullptr;
5857 "AAExecutionDomain can only be created for function position!");
5859 AA =
new (
A.Allocator) AAExecutionDomainFunction(IRP,
A);
5866AAHeapToShared &AAHeapToShared::createForPosition(
const IRPosition &IRP,
5868 AAHeapToSharedFunction *
AA =
nullptr;
5878 "AAHeapToShared can only be created for function position!");
5880 AA =
new (
A.Allocator) AAHeapToSharedFunction(IRP,
A);
5887AAKernelInfo &AAKernelInfo::createForPosition(
const IRPosition &IRP,
5889 AAKernelInfo *AA =
nullptr;
5899 AA =
new (
A.Allocator) AAKernelInfoCallSite(IRP,
A);
5902 AA =
new (
A.Allocator) AAKernelInfoFunction(IRP,
A);
5909AAFoldRuntimeCall &AAFoldRuntimeCall::createForPosition(
const IRPosition &IRP,
5911 AAFoldRuntimeCall *AA =
nullptr;
5920 llvm_unreachable(
"KernelInfo can only be created for call site position!");
5922 AA =
new (
A.Allocator) AAFoldRuntimeCallCallSiteReturned(IRP,
A);
5942 unsigned NumAssumedCallees) {
5960 if (Kernels.contains(&
F))
5962 return !
F.use_empty();
5969 return ORA <<
"Could not internalize function. "
5970 <<
"Some optimizations may not be possible. [OMP140]";
5982 if (!
F.isDeclaration() && !Kernels.contains(&
F) && IsCalled(
F) &&
5986 }
else if (!
F.hasLocalLinkage() && !
F.hasFnAttribute(Attribute::Cold)) {
5999 if (!
F.isDeclaration() && !InternalizedMap.
lookup(&
F)) {
6001 Functions.insert(&
F);
6019 OMPInformationCache InfoCache(M, AG, Allocator,
nullptr, PostLink);
6021 unsigned MaxFixpointIterations =
6034 return F.hasFnAttribute(
"kernel");
6039 OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache,
A);
6045 if (!
F.isDeclaration() && !Kernels.contains(&
F) &&
6046 !
F.hasFnAttribute(Attribute::NoInline))
6047 F.addFnAttr(Attribute::AlwaysInline);
6077 Module &M = *
C.begin()->getFunction().getParent();
6099 OMPInformationCache InfoCache(*(Functions.back()->getParent()), AG, Allocator,
6100 &Functions, PostLink);
6102 unsigned MaxFixpointIterations =
6117 OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache,
A);
6118 bool Changed = OMPOpt.run(
false);
6137 if (
F.hasKernelCallingConv()) {
6142 ++NumOpenMPTargetRegionKernels;
6145 ++NumNonOpenMPTargetRegionKernels;
6152 Metadata *MD = M.getModuleFlag(
"openmp");
6160 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.
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.
static cl::opt< unsigned > MaxThreads("xcore-max-threads", cl::Optional, cl::desc("Maximum number of threads (for emulation thread-local storage)"), cl::Hidden, cl::value_desc("number"), cl::init(8))
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
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 (...
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.
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.
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 ...
BasicBlock * getBlock() const
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 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 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.
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.
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.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
MutableArrayRef(T &OneElt) -> MutableArrayRef< T >
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
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.
LLVM_ABI const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=MaxLookupSearchDepth)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
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),...