51#include "llvm/IR/IntrinsicsAMDGPU.h"
52#include "llvm/IR/IntrinsicsNVPTX.h"
72#define DEBUG_TYPE "openmp-opt"
75 "openmp-opt-disable",
cl::desc(
"Disable OpenMP specific optimizations."),
79 "openmp-opt-enable-merging",
85 cl::desc(
"Disable function internalization."),
96 "openmp-hide-memory-transfer-latency",
97 cl::desc(
"[WIP] Tries to hide the latency of host to device memory"
102 "openmp-opt-disable-deglobalization",
103 cl::desc(
"Disable OpenMP optimizations involving deglobalization."),
107 "openmp-opt-disable-spmdization",
108 cl::desc(
"Disable OpenMP optimizations involving SPMD-ization."),
112 "openmp-opt-disable-folding",
117 "openmp-opt-disable-state-machine-rewrite",
118 cl::desc(
"Disable OpenMP optimizations that replace the state machine."),
122 "openmp-opt-disable-barrier-elimination",
123 cl::desc(
"Disable OpenMP optimizations that eliminate barriers."),
127 "openmp-opt-print-module-after",
128 cl::desc(
"Print the current module after OpenMP optimizations."),
132 "openmp-opt-print-module-before",
133 cl::desc(
"Print the current module before OpenMP optimizations."),
137 "openmp-opt-inline-device",
148 cl::desc(
"Maximal number of attributor iterations."),
153 cl::desc(
"Maximum amount of shared memory to use."),
154 cl::init(std::numeric_limits<unsigned>::max()));
157 "openmp-opt-max-callees-for-specialization",
cl::Hidden,
158 cl::desc(
"Number of possible callees above which an indirect call site is "
159 "left alone rather than specialized into an if-cascade."),
163 "Number of OpenMP runtime calls deduplicated");
165 "Number of OpenMP parallel regions deleted");
167 "Number of OpenMP runtime functions identified");
169 "Number of OpenMP runtime function uses identified");
171 "Number of OpenMP target region entry points (=kernels) identified");
173 "Number of non-OpenMP target region kernels identified");
175 "Number of OpenMP target region entry points (=kernels) executed in "
176 "SPMD-mode instead of generic-mode");
177STATISTIC(NumOpenMPTargetRegionKernelsWithoutStateMachine,
178 "Number of OpenMP target region entry points (=kernels) executed in "
179 "generic-mode without a state machines");
180STATISTIC(NumOpenMPTargetRegionKernelsCustomStateMachineWithFallback,
181 "Number of OpenMP target region entry points (=kernels) executed in "
182 "generic-mode with customized state machines with fallback");
183STATISTIC(NumOpenMPTargetRegionKernelsCustomStateMachineWithoutFallback,
184 "Number of OpenMP target region entry points (=kernels) executed in "
185 "generic-mode with customized state machines without fallback");
187 NumOpenMPParallelRegionsReplacedInGPUStateMachine,
188 "Number of OpenMP parallel regions replaced with ID in GPU state machines");
190 "Number of OpenMP parallel regions merged");
192 "Amount of memory pushed to shared memory");
193STATISTIC(NumBarriersEliminated,
"Number of redundant barriers eliminated");
221#define KERNEL_ENVIRONMENT_IDX(MEMBER, IDX) \
222 constexpr unsigned MEMBER##Idx = IDX;
227#undef KERNEL_ENVIRONMENT_IDX
229#define KERNEL_ENVIRONMENT_CONFIGURATION_IDX(MEMBER, IDX) \
230 constexpr unsigned MEMBER##Idx = IDX;
240#undef KERNEL_ENVIRONMENT_CONFIGURATION_IDX
242#define KERNEL_ENVIRONMENT_GETTER(MEMBER, RETURNTYPE) \
243 RETURNTYPE *get##MEMBER##FromKernelEnvironment(ConstantStruct *KernelEnvC) { \
244 return cast<RETURNTYPE>(KernelEnvC->getAggregateElement(MEMBER##Idx)); \
250#undef KERNEL_ENVIRONMENT_GETTER
252#define KERNEL_ENVIRONMENT_CONFIGURATION_GETTER(MEMBER) \
253 ConstantInt *get##MEMBER##FromKernelEnvironment( \
254 ConstantStruct *KernelEnvC) { \
255 ConstantStruct *ConfigC = \
256 getConfigurationFromKernelEnvironment(KernelEnvC); \
257 return dyn_cast<ConstantInt>(ConfigC->getAggregateElement(MEMBER##Idx)); \
268#undef KERNEL_ENVIRONMENT_CONFIGURATION_GETTER
272 constexpr int InitKernelEnvironmentArgNo = 0;
287struct AAHeapToShared;
294 OMPInformationCache(
Module &M, AnalysisGetter &AG,
298 OpenMPPostLink(OpenMPPostLink) {
301 const Triple
T(OMPBuilder.M.getTargetTriple());
302 switch (
T.getArch()) {
306 assert(OMPBuilder.Config.IsTargetDevice &&
307 "OpenMP AMDGPU/NVPTX is only prepared to deal with device code.");
308 OMPBuilder.Config.IsGPU =
true;
311 OMPBuilder.Config.IsGPU =
false;
314 OMPBuilder.initialize();
315 initializeRuntimeFunctions(M);
316 initializeInternalControlVars();
320 struct InternalControlVarInfo {
328 StringRef EnvVarName;
334 ConstantInt *InitValue;
347 struct RuntimeFunctionInfo {
368 using UseVector = SmallVector<Use *, 16>;
371 void clearUsesMap() { UsesMap.clear(); }
374 operator bool()
const {
return Declaration; }
377 UseVector &getOrCreateUseVector(
Function *
F) {
378 std::shared_ptr<UseVector> &UV = UsesMap[
F];
380 UV = std::make_shared<UseVector>();
386 const UseVector *getUseVector(
Function &
F)
const {
387 auto I = UsesMap.find(&
F);
388 if (
I != UsesMap.end())
389 return I->second.get();
394 size_t getNumFunctionsWithUses()
const {
return UsesMap.size(); }
398 size_t getNumArgs()
const {
return ArgumentTypes.size(); }
403 void foreachUse(SmallVectorImpl<Function *> &SCC,
404 function_ref<
bool(Use &,
Function &)> CB) {
412 SmallVector<unsigned, 8> ToBeDeleted;
416 UseVector &UV = getOrCreateUseVector(
F);
426 while (!ToBeDeleted.
empty()) {
436 DenseMap<Function *, std::shared_ptr<UseVector>> UsesMap;
440 decltype(UsesMap)::iterator
begin() {
return UsesMap.begin(); }
441 decltype(UsesMap)::iterator
end() {
return UsesMap.end(); }
445 OpenMPIRBuilder OMPBuilder;
449 RuntimeFunction::OMPRTL___last>
453 DenseMap<Function *, RuntimeFunction> RuntimeFunctionIDMap;
457 InternalControlVar::ICV___last>
462 void initializeInternalControlVars() {
463#define ICV_RT_SET(_Name, RTL) \
465 auto &ICV = ICVs[_Name]; \
468#define ICV_RT_GET(Name, RTL) \
470 auto &ICV = ICVs[Name]; \
473#define ICV_DATA_ENV(Enum, _Name, _EnvVarName, Init) \
475 auto &ICV = ICVs[Enum]; \
478 ICV.InitKind = Init; \
479 ICV.EnvVarName = _EnvVarName; \
480 switch (ICV.InitKind) { \
481 case ICV_IMPLEMENTATION_DEFINED: \
482 ICV.InitValue = nullptr; \
485 ICV.InitValue = ConstantInt::get( \
486 Type::getInt32Ty(OMPBuilder.Int32->getContext()), 0); \
489 ICV.InitValue = ConstantInt::getFalse(OMPBuilder.Int1->getContext()); \
495#include "llvm/Frontend/OpenMP/OMPKinds.def"
501 static bool declMatchesRTFTypes(
Function *
F,
Type *RTFRetType,
508 if (
F->getReturnType() != RTFRetType)
510 if (
F->arg_size() != RTFArgTypes.
size())
513 auto *RTFTyIt = RTFArgTypes.
begin();
514 for (Argument &Arg :
F->args()) {
515 if (Arg.getType() != *RTFTyIt)
525 unsigned collectUses(RuntimeFunctionInfo &RFI,
bool CollectStats =
true) {
526 unsigned NumUses = 0;
527 if (!RFI.Declaration)
529 OMPBuilder.addAttributes(RFI.Kind, *RFI.Declaration);
532 NumOpenMPRuntimeFunctionsIdentified += 1;
533 NumOpenMPRuntimeFunctionUsesIdentified += RFI.Declaration->getNumUses();
537 for (Use &U : RFI.Declaration->uses()) {
539 if (!
CGSCC ||
CGSCC->empty() ||
CGSCC->contains(UserI->getFunction())) {
540 RFI.getOrCreateUseVector(UserI->getFunction()).push_back(&U);
544 RFI.getOrCreateUseVector(
nullptr).push_back(&U);
553 auto &RFI = RFIs[RTF];
555 collectUses(RFI,
false);
563 void setCallbackMetadata(
Function *
F,
unsigned ArgNo, ArrayRef<int> Indices,
565 if (!
F ||
F->hasMetadata(LLVMContext::MD_callback))
568 LLVMContext &Ctx =
F->getContext();
570 F->addMetadata(LLVMContext::MD_callback,
571 *
MDNode::get(Ctx, {MDB.createCallbackEncoding(ArgNo, Indices,
579 static Function *getAnalyzableCallback(
const CallBase &CB) {
583 MDNode *CallbackMD =
Callee->getMetadata(LLVMContext::MD_callback);
589 if (!Encoding || Encoding->getNumOperands() == 0)
600 if (!Callback ||
Callback->isDeclaration())
606 void recollectUses() {
607 for (
int Idx = 0; Idx < RFIs.size(); ++Idx)
612 void setCallingConvention(FunctionCallee Callee, CallInst *CI) {
627 RuntimeFunctionInfo &RFI = RFIs[Fn];
629 if (!RFI.Declaration || RFI.Declaration->isDeclaration())
637 void initializeRuntimeFunctions(
Module &M) {
640#define OMP_TYPE(VarName, ...) \
641 Type *VarName = OMPBuilder.VarName; \
644#define OMP_ARRAY_TYPE(VarName, ...) \
645 ArrayType *VarName##Ty = OMPBuilder.VarName##Ty; \
647 PointerType *VarName##PtrTy = OMPBuilder.VarName##PtrTy; \
648 (void)VarName##PtrTy;
650#define OMP_FUNCTION_TYPE(VarName, ...) \
651 FunctionType *VarName = OMPBuilder.VarName; \
653 PointerType *VarName##Ptr = OMPBuilder.VarName##Ptr; \
656#define OMP_STRUCT_TYPE(VarName, ...) \
657 StructType *VarName = OMPBuilder.VarName; \
659 PointerType *VarName##Ptr = OMPBuilder.VarName##Ptr; \
662#define OMP_RTL(_Enum, _Name, _IsVarArg, _ReturnType, ...) \
664 SmallVector<Type *, 8> ArgsTypes({__VA_ARGS__}); \
665 Function *F = M.getFunction(_Name); \
666 RTLFunctions.insert(F); \
667 if (declMatchesRTFTypes(F, OMPBuilder._ReturnType, ArgsTypes)) { \
668 RuntimeFunctionIDMap[F] = _Enum; \
669 auto &RFI = RFIs[_Enum]; \
672 RFI.IsVarArg = _IsVarArg; \
673 RFI.ReturnType = OMPBuilder._ReturnType; \
674 RFI.ArgumentTypes = std::move(ArgsTypes); \
675 RFI.Declaration = F; \
676 unsigned NumUses = collectUses(RFI); \
679 dbgs() << TAG << RFI.Name << (RFI.Declaration ? "" : " not") \
681 if (RFI.Declaration) \
682 dbgs() << TAG << "-> got " << NumUses << " uses in " \
683 << RFI.getNumFunctionsWithUses() \
684 << " different functions.\n"; \
689#define OMP_RTL_CB_INFO(_Enum, _Name, _ArgNo, _ArgIndices, _IsVarArg) \
690 setCallbackMetadata(M.getFunction(_Name), _ArgNo, _ArgIndices, _IsVarArg);
692#include "llvm/Frontend/OpenMP/OMPKinds.def"
698 for (StringRef Prefix : {
"__kmpc",
"_ZN4ompx",
"omp_"})
699 if (
F.hasFnAttribute(Attribute::NoInline) &&
700 F.getName().starts_with(Prefix) &&
701 !
F.hasFnAttribute(Attribute::OptimizeNone))
702 F.removeFnAttr(Attribute::NoInline);
710 DenseSet<const Function *> RTLFunctions;
713 bool OpenMPPostLink =
false;
720 SmallPtrSet<Function *, 8> SPMDizedKernels;
723template <
typename Ty,
bool InsertInval
idates = true>
725 bool contains(
const Ty &Elem)
const {
return Set.contains(Elem); }
726 bool insert(
const Ty &Elem) {
727 if (InsertInvalidates)
728 BooleanState::indicatePessimisticFixpoint();
729 return Set.insert(Elem);
732 const Ty &operator[](
int Idx)
const {
return Set[Idx]; }
733 bool operator==(
const BooleanStateWithSetVector &
RHS)
const {
734 return BooleanState::operator==(
RHS) && Set ==
RHS.Set;
736 bool operator!=(
const BooleanStateWithSetVector &
RHS)
const {
737 return !(*
this ==
RHS);
740 bool empty()
const {
return Set.empty(); }
741 size_t size()
const {
return Set.size(); }
744 BooleanStateWithSetVector &
operator^=(
const BooleanStateWithSetVector &
RHS) {
745 BooleanState::operator^=(
RHS);
746 Set.insert_range(
RHS.Set);
755 typename decltype(Set)::iterator
begin() {
return Set.begin(); }
756 typename decltype(Set)::iterator
end() {
return Set.end(); }
757 typename decltype(Set)::const_iterator
begin()
const {
return Set.begin(); }
758 typename decltype(Set)::const_iterator
end()
const {
return Set.end(); }
761template <
typename Ty,
bool InsertInval
idates = true>
762using BooleanStateWithPtrSetVector =
763 BooleanStateWithSetVector<Ty *, InsertInvalidates>;
767 bool IsAtFixpoint =
false;
771 BooleanStateWithPtrSetVector<CallBase,
false>
772 ReachedKnownParallelRegions;
775 BooleanStateWithPtrSetVector<CallBase> ReachedUnknownParallelRegions;
780 BooleanStateWithPtrSetVector<Instruction, false> SPMDCompatibilityTracker;
784 CallBase *KernelInitCB =
nullptr;
788 ConstantStruct *KernelEnvC =
nullptr;
792 CallBase *KernelDeinitCB =
nullptr;
795 bool IsKernelEntry =
false;
798 BooleanStateWithPtrSetVector<Function, false> ReachingKernelEntries;
803 BooleanStateWithSetVector<uint8_t> ParallelLevels;
806 bool NestedParallelism =
false;
811 KernelInfoState() =
default;
812 KernelInfoState(
bool BestState) {
814 indicatePessimisticFixpoint();
818 bool isValidState()
const override {
return true; }
821 bool isAtFixpoint()
const override {
return IsAtFixpoint; }
826 ParallelLevels.indicatePessimisticFixpoint();
827 ReachingKernelEntries.indicatePessimisticFixpoint();
828 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
829 ReachedKnownParallelRegions.indicatePessimisticFixpoint();
830 ReachedUnknownParallelRegions.indicatePessimisticFixpoint();
831 NestedParallelism =
true;
832 return ChangeStatus::CHANGED;
838 ParallelLevels.indicateOptimisticFixpoint();
839 ReachingKernelEntries.indicateOptimisticFixpoint();
840 SPMDCompatibilityTracker.indicateOptimisticFixpoint();
841 ReachedKnownParallelRegions.indicateOptimisticFixpoint();
842 ReachedUnknownParallelRegions.indicateOptimisticFixpoint();
843 return ChangeStatus::UNCHANGED;
847 KernelInfoState &getAssumed() {
return *
this; }
848 const KernelInfoState &getAssumed()
const {
return *
this; }
851 if (SPMDCompatibilityTracker !=
RHS.SPMDCompatibilityTracker)
853 if (ReachedKnownParallelRegions !=
RHS.ReachedKnownParallelRegions)
855 if (ReachedUnknownParallelRegions !=
RHS.ReachedUnknownParallelRegions)
857 if (ReachingKernelEntries !=
RHS.ReachingKernelEntries)
859 if (ParallelLevels !=
RHS.ParallelLevels)
861 if (NestedParallelism !=
RHS.NestedParallelism)
867 bool mayContainParallelRegion() {
868 return !ReachedKnownParallelRegions.empty() ||
869 !ReachedUnknownParallelRegions.empty();
873 static KernelInfoState getBestState() {
return KernelInfoState(
true); }
875 static KernelInfoState getBestState(KernelInfoState &KIS) {
876 return getBestState();
880 static KernelInfoState getWorstState() {
return KernelInfoState(
false); }
883 KernelInfoState
operator^=(
const KernelInfoState &KIS) {
885 if (KIS.KernelInitCB) {
886 if (KernelInitCB && KernelInitCB != KIS.KernelInitCB)
889 KernelInitCB = KIS.KernelInitCB;
891 if (KIS.KernelDeinitCB) {
892 if (KernelDeinitCB && KernelDeinitCB != KIS.KernelDeinitCB)
895 KernelDeinitCB = KIS.KernelDeinitCB;
897 if (KIS.KernelEnvC) {
898 if (KernelEnvC && KernelEnvC != KIS.KernelEnvC)
901 KernelEnvC = KIS.KernelEnvC;
903 SPMDCompatibilityTracker ^= KIS.SPMDCompatibilityTracker;
904 ReachedKnownParallelRegions ^= KIS.ReachedKnownParallelRegions;
905 ReachedUnknownParallelRegions ^= KIS.ReachedUnknownParallelRegions;
906 NestedParallelism |= KIS.NestedParallelism;
910 KernelInfoState
operator&=(
const KernelInfoState &KIS) {
911 return (*
this ^= KIS);
921 AllocaInst *Array =
nullptr;
923 SmallVector<Value *, 8> StoredValues;
925 SmallVector<StoreInst *, 8> LastAccesses;
927 OffloadArray() =
default;
933 bool initialize(AllocaInst &Array, Instruction &Before) {
934 if (!getValues(Array, Before))
937 this->Array = &Array;
941 static const unsigned DeviceIDArgNum = 1;
942 static const unsigned BasePtrsArgNum = 3;
943 static const unsigned PtrsArgNum = 4;
944 static const unsigned SizesArgNum = 5;
950 bool getValues(AllocaInst &Array, Instruction &Before) {
952 const DataLayout &
DL = Array.getDataLayout();
953 std::optional<TypeSize> ArraySize = Array.getAllocationSize(
DL);
954 if (!ArraySize || !ArraySize->isFixed())
958 StoredValues.assign(NumValues,
nullptr);
959 LastAccesses.assign(NumValues,
nullptr);
967 for (Instruction &
I : *BB) {
983 LastAccesses[Idx] = S;
994 const unsigned NumValues = StoredValues.size();
995 for (
unsigned I = 0;
I < NumValues; ++
I) {
996 if (!StoredValues[
I] || !LastAccesses[
I])
1007static std::optional<uint64_t>
1009 unsigned CallbackOpNo) {
1010 std::optional<uint64_t> EntryCount;
1016 if (std::optional<uint64_t> EC =
Callback->getEntryCount())
1019 EntryCount = EntryCount ? std::max(*EntryCount, *EC) : *
EC;
1024static bool moduleHasSampleProfile(
const Module &M) {
1025 std::unique_ptr<ProfileSummary> Summary(
1032 using OptimizationRemarkGetter =
1033 function_ref<OptimizationRemarkEmitter &(
Function *)>;
1035 OpenMPOpt(SmallVectorImpl<Function *> &SCC, CallGraphUpdater &CGUpdater,
1036 OptimizationRemarkGetter OREGetter,
1037 OMPInformationCache &OMPInfoCache, Attributor &A)
1038 : M(*(*SCC.
begin())->
getParent()), SCC(SCC), CGUpdater(CGUpdater),
1039 OREGetter(OREGetter), OMPInfoCache(OMPInfoCache), A(A) {}
1042 bool remarksEnabled() {
1043 auto &Ctx = M.getContext();
1048 bool run(
bool IsModulePass) {
1058 Changed |= runAttributor(IsModulePass);
1061 OMPInfoCache.recollectUses();
1064 Changed |= rewriteDeviceCodeStateMachine();
1070 Changed |= removeSPMDParallelWrappers();
1072 if (remarksEnabled())
1073 analysisGlobalization();
1080 Changed |= runAttributor(IsModulePass);
1083 OMPInfoCache.recollectUses();
1085 Changed |= deleteParallelRegions();
1088 Changed |= hideMemTransfersLatency();
1089 Changed |= deduplicateRuntimeCalls();
1091 if (mergeParallelRegions()) {
1092 deduplicateRuntimeCalls();
1098 if (OMPInfoCache.OpenMPPostLink)
1099 Changed |= removeRuntimeSymbols();
1106 void printICVs()
const {
1111 for (
auto ICV : ICVs) {
1112 auto ICVInfo = OMPInfoCache.ICVs[ICV];
1113 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
1114 return ORA <<
"OpenMP ICV " <<
ore::NV(
"OpenMPICV", ICVInfo.Name)
1116 << (ICVInfo.InitValue
1117 ?
toString(ICVInfo.InitValue->getValue(), 10,
true)
1118 :
"IMPLEMENTATION_DEFINED");
1127 void printKernels()
const {
1132 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
1133 return ORA <<
"OpenMP GPU kernel "
1134 <<
ore::NV(
"OpenMPGPUKernel",
F->getName()) <<
"\n";
1143 static CallInst *getCallIfRegularCall(
1144 Use &U, OMPInformationCache::RuntimeFunctionInfo *RFI =
nullptr) {
1155 static CallInst *getCallIfRegularCall(
1156 Value &V, OMPInformationCache::RuntimeFunctionInfo *RFI =
nullptr) {
1167 bool mergeParallelRegions() {
1168 const unsigned CallbackCalleeOperand = 2;
1169 const unsigned CallbackFirstArgOperand = 3;
1173 OMPInformationCache::RuntimeFunctionInfo &RFI =
1174 OMPInfoCache.RFIs[OMPRTL___kmpc_fork_call];
1176 if (!RFI.Declaration)
1180 OMPInformationCache::RuntimeFunctionInfo UnmergableCallsInfo[] = {
1181 OMPInfoCache.RFIs[OMPRTL___kmpc_push_proc_bind],
1182 OMPInfoCache.RFIs[OMPRTL___kmpc_push_num_threads],
1186 LoopInfo *LI =
nullptr;
1187 DominatorTree *DT =
nullptr;
1189 SmallDenseMap<BasicBlock *, SmallPtrSet<Instruction *, 4>> BB2PRMap;
1191 BasicBlock *StartBB =
nullptr, *EndBB =
nullptr;
1192 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
1194 BasicBlock *CGStartBB = CodeGenIP.getNodeParent();
1196 assert(StartBB !=
nullptr &&
"StartBB should not be null");
1198 assert(EndBB !=
nullptr &&
"EndBB should not be null");
1199 EndBB->getTerminator()->setSuccessor(0, CGEndBB);
1203 auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
Value &,
1204 Value &Inner,
Value *&ReplacementValue) -> InsertPointTy {
1205 ReplacementValue = &Inner;
1209 auto FiniCB = [&](InsertPointTy CodeGenIP) {
return Error::success(); };
1213 auto CreateSequentialRegion = [&](
Function *OuterFn,
1219 BasicBlock *ParentBB = SeqStartI->getParent();
1221 SplitBlock(ParentBB, SeqEndI->getNextNode(), DT, LI);
1225 SplitBlock(ParentBB, SeqStartI, DT, LI,
nullptr,
"seq.par.merged");
1228 "Expected a different CFG");
1232 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
1234 BasicBlock *CGStartBB = CodeGenIP.getNodeParent();
1236 assert(SeqStartBB !=
nullptr &&
"SeqStartBB should not be null");
1238 assert(SeqEndBB !=
nullptr &&
"SeqEndBB should not be null");
1242 auto FiniCB = [&](InsertPointTy CodeGenIP) {
return Error::success(); };
1246 for (Instruction &
I : *SeqStartBB) {
1247 SmallPtrSet<Instruction *, 4> OutsideUsers;
1248 for (User *Usr :
I.users()) {
1256 OutsideUsers.
insert(&UsrI);
1259 if (OutsideUsers.
empty())
1264 const DataLayout &
DL = M.getDataLayout();
1265 AllocaInst *AllocaI =
new AllocaInst(
1266 I.getType(),
DL.getAllocaAddrSpace(),
nullptr,
1271 new StoreInst(&
I, AllocaI, SeqStartBB->getTerminator()->getIterator());
1275 for (Instruction *UsrI : OutsideUsers) {
1276 LoadInst *LoadI =
new LoadInst(
I.getType(), AllocaI,
1277 I.getName() +
".seq.output.load",
1283 OpenMPIRBuilder::LocationDescription Loc(ParentBB->
end(),
DL);
1285 OMPInfoCache.OMPBuilder.createMaster(Loc, BodyGenCB, FiniCB));
1286 cantFail(OMPInfoCache.OMPBuilder.createBarrier({SeqAfterIP, DL},
1302 auto Merge = [&](
const SmallVectorImpl<CallInst *> &MergableCIs,
1306 assert(MergableCIs.
size() > 1 &&
"Assumed multiple mergable CIs");
1308 auto Remark = [&](OptimizationRemark
OR) {
1309 OR <<
"Parallel region merged with parallel region"
1310 << (MergableCIs.
size() > 2 ?
"s" :
"") <<
" at ";
1313 if (CI != MergableCIs.
back())
1321 Function *OriginalFn = BB->getParent();
1323 <<
" parallel regions in " << OriginalFn->
getName()
1327 EndBB =
SplitBlock(BB, MergableCIs.
back()->getNextNode(), DT, LI);
1329 SplitBlock(EndBB, &*EndBB->getFirstInsertionPt(), DT, LI);
1333 assert(BB->getUniqueSuccessor() == StartBB &&
"Expected a different CFG");
1334 const DebugLoc DL = BB->getTerminator()->getDebugLoc();
1339 for (
auto *It = MergableCIs.
begin(), *End = MergableCIs.
end() - 1;
1348 CreateSequentialRegion(OriginalFn, BB, ForkCI->
getNextNode(),
1352 OpenMPIRBuilder::LocationDescription Loc(BB->end(),
DL);
1353 IRBuilder<>::InsertPoint AllocaIP(
1358 cantFail(OMPInfoCache.OMPBuilder.createParallel(
1359 Loc, AllocaIP, {}, BodyGenCB, PrivCB, FiniCB,
1360 nullptr,
nullptr, OMP_PROC_BIND_default,
1365 OMPInfoCache.OMPBuilder.finalize(OriginalFn);
1368 std::optional<uint64_t> WrapperCount =
1369 getMergedWrapperEntryCount(MergableCIs, CallbackCalleeOperand);
1375 const bool SampleProfile =
1376 moduleHasSampleProfile(*OriginalFn->
getParent());
1380 SmallVector<Value *, 8>
Args;
1381 for (
auto *CI : MergableCIs) {
1383 FunctionType *FT = OMPInfoCache.OMPBuilder.ParallelTask;
1387 for (
unsigned U = CallbackFirstArgOperand,
E = CI->
arg_size(); U <
E;
1397 if (WrapperCount && SampleProfile) {
1403 for (
unsigned U = CallbackFirstArgOperand,
E = CI->
arg_size(); U <
E;
1407 U - (CallbackFirstArgOperand - CallbackCalleeOperand), A);
1410 if (CI != MergableCIs.back()) {
1413 cantFail(OMPInfoCache.OMPBuilder.createBarrier(
1414 {NewCI->getNextNode()->getIterator(), NewCI->getDebugLoc()},
1421 assert(OutlinedFn != OriginalFn &&
"Outlining failed");
1422 CGUpdater.registerOutlinedFunction(*OriginalFn, *OutlinedFn);
1423 CGUpdater.reanalyzeFunction(*OriginalFn);
1425 NumOpenMPParallelRegionsMerged += MergableCIs.size();
1433 CallInst *CI = getCallIfRegularCall(U, &RFI);
1440 RFI.foreachUse(SCC, DetectPRsCB);
1446 for (
auto &It : BB2PRMap) {
1447 auto &CIs = It.getSecond();
1462 auto IsMergable = [&](
Instruction &
I,
bool IsBeforeMergableRegion) {
1465 if (
I.isTerminator())
1472 if (IsBeforeMergableRegion) {
1474 if (!CalledFunction)
1481 for (
const auto &RFI : UnmergableCallsInfo) {
1482 if (CalledFunction == RFI.Declaration)
1497 for (
auto It = BB->
begin(), End = BB->
end(); It != End;) {
1501 if (CIs.count(&
I)) {
1507 if (IsMergable(
I, MergableCIs.
empty()))
1512 for (; It != End; ++It) {
1514 if (CIs.count(&SkipI)) {
1516 <<
" due to " <<
I <<
"\n");
1523 if (MergableCIs.
size() > 1) {
1524 MergableCIsVector.
push_back(MergableCIs);
1526 <<
" parallel regions in block " << BB->
getName()
1531 MergableCIs.
clear();
1534 if (!MergableCIsVector.
empty()) {
1537 for (
auto &MergableCIs : MergableCIsVector)
1538 Merge(MergableCIs, BB);
1539 MergableCIsVector.clear();
1546 OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_fork_call);
1547 OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_barrier);
1548 OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_master);
1549 OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_end_master);
1556 bool deleteParallelRegions() {
1557 const unsigned CallbackCalleeOperand = 2;
1559 OMPInformationCache::RuntimeFunctionInfo &RFI =
1560 OMPInfoCache.RFIs[OMPRTL___kmpc_fork_call];
1562 if (!RFI.Declaration)
1567 CallInst *CI = getCallIfRegularCall(U);
1574 if (!Fn->onlyReadsMemory())
1576 if (!Fn->hasFnAttribute(Attribute::WillReturn))
1582 auto Remark = [&](OptimizationRemark
OR) {
1583 return OR <<
"Removing parallel region with no side-effects.";
1589 ++NumOpenMPParallelRegionsDeleted;
1593 RFI.foreachUse(SCC, DeleteCallCB);
1599 bool deduplicateRuntimeCalls() {
1603 OMPRTL_omp_get_num_threads,
1604 OMPRTL_omp_in_parallel,
1605 OMPRTL_omp_get_cancellation,
1606 OMPRTL_omp_get_supported_active_levels,
1607 OMPRTL_omp_get_level,
1608 OMPRTL_omp_get_ancestor_thread_num,
1609 OMPRTL_omp_get_team_size,
1610 OMPRTL_omp_get_active_level,
1611 OMPRTL_omp_in_final,
1612 OMPRTL_omp_get_proc_bind,
1613 OMPRTL_omp_get_num_places,
1614 OMPRTL_omp_get_num_procs,
1615 OMPRTL_omp_get_place_num,
1616 OMPRTL_omp_get_partition_num_places,
1617 OMPRTL_omp_get_partition_place_nums};
1620 SmallSetVector<Value *, 16> GTIdArgs;
1621 collectGlobalThreadIdArguments(GTIdArgs);
1623 <<
" global thread ID arguments\n");
1626 for (
auto DeduplicableRuntimeCallID : DeduplicableRuntimeCallIDs)
1627 Changed |= deduplicateRuntimeCalls(
1628 *
F, OMPInfoCache.RFIs[DeduplicableRuntimeCallID]);
1632 Value *GTIdArg =
nullptr;
1633 for (Argument &Arg :
F->args())
1634 if (GTIdArgs.
count(&Arg)) {
1638 Changed |= deduplicateRuntimeCalls(
1639 *
F, OMPInfoCache.RFIs[OMPRTL___kmpc_global_thread_num], GTIdArg);
1646 bool removeRuntimeSymbols() {
1651 if (GlobalVariable *GV = M.getNamedGlobal(
"__llvm_rpc_client")) {
1652 if (GV->hasNUsesOrMore(1))
1656 GV->eraseFromParent();
1668 bool hideMemTransfersLatency() {
1669 auto &RFI = OMPInfoCache.RFIs[OMPRTL___tgt_target_data_begin_mapper];
1672 auto *RTCall = getCallIfRegularCall(U, &RFI);
1676 OffloadArray OffloadArrays[3];
1677 if (!getValuesInOffloadArrays(*RTCall, OffloadArrays))
1680 LLVM_DEBUG(dumpValuesInOffloadArrays(OffloadArrays));
1683 bool WasSplit =
false;
1684 Instruction *WaitMovementPoint = canBeMovedDownwards(*RTCall);
1685 if (WaitMovementPoint)
1686 WasSplit = splitTargetDataBeginRTC(*RTCall, *WaitMovementPoint);
1691 if (OMPInfoCache.runtimeFnsAvailable(
1692 {OMPRTL___tgt_target_data_begin_mapper_issue,
1693 OMPRTL___tgt_target_data_begin_mapper_wait}))
1694 RFI.foreachUse(SCC, SplitMemTransfers);
1699 void analysisGlobalization() {
1700 auto &RFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
1702 auto CheckGlobalization = [&](
Use &
U,
Function &Decl) {
1703 if (CallInst *CI = getCallIfRegularCall(U, &RFI)) {
1704 auto Remark = [&](OptimizationRemarkMissed ORM) {
1706 <<
"Found thread data sharing on the GPU. "
1707 <<
"Expect degraded performance due to data globalization.";
1715 RFI.foreachUse(SCC, CheckGlobalization);
1720 bool getValuesInOffloadArrays(CallInst &RuntimeCall,
1722 assert(OAs.
size() == 3 &&
"Need space for three offload arrays!");
1732 Value *BasePtrsArg =
1744 if (!OAs[0].
initialize(*BasePtrsArray, RuntimeCall))
1752 if (!OAs[1].
initialize(*PtrsArray, RuntimeCall))
1764 if (!OAs[2].
initialize(*SizesArray, RuntimeCall))
1775 assert(OAs.
size() == 3 &&
"There are three offload arrays to debug!");
1778 std::string ValuesStr;
1779 raw_string_ostream
Printer(ValuesStr);
1780 std::string Separator =
" --- ";
1782 for (
auto *BP : OAs[0].StoredValues) {
1786 LLVM_DEBUG(
dbgs() <<
"\t\toffload_baseptrs: " << ValuesStr <<
"\n");
1789 for (
auto *
P : OAs[1].StoredValues) {
1796 for (
auto *S : OAs[2].StoredValues) {
1800 LLVM_DEBUG(
dbgs() <<
"\t\toffload_sizes: " << ValuesStr <<
"\n");
1805 Instruction *canBeMovedDownwards(CallInst &RuntimeCall) {
1810 bool IsWorthIt =
false;
1829 return RuntimeCall.
getParent()->getTerminator();
1833 bool splitTargetDataBeginRTC(CallInst &RuntimeCall,
1834 Instruction &WaitMovementPoint) {
1838 auto &
IRBuilder = OMPInfoCache.OMPBuilder;
1841 IRBuilder.Builder.SetInsertPoint(
Entry.getFirstNonPHIOrDbgOrAlloca());
1843 IRBuilder.AsyncInfo,
nullptr,
"handle");
1850 FunctionCallee IssueDecl =
IRBuilder.getOrCreateRuntimeFunction(
1851 M, OMPRTL___tgt_target_data_begin_mapper_issue);
1854 SmallVector<Value *, 16>
Args;
1855 for (
auto &Arg : RuntimeCall.
args())
1856 Args.push_back(Arg.get());
1857 Args.push_back(Handle);
1861 OMPInfoCache.setCallingConvention(IssueDecl, IssueCallsite);
1866 FunctionCallee WaitDecl =
IRBuilder.getOrCreateRuntimeFunction(
1867 M, OMPRTL___tgt_target_data_begin_mapper_wait);
1869 Value *WaitParams[2] = {
1871 OffloadArray::DeviceIDArgNum),
1875 WaitDecl, WaitParams,
"", WaitMovementPoint.
getIterator());
1876 OMPInfoCache.setCallingConvention(WaitDecl, WaitCallsite);
1881 static Value *combinedIdentStruct(
Value *CurrentIdent,
Value *NextIdent,
1882 bool GlobalOnly,
bool &SingleChoice) {
1883 if (CurrentIdent == NextIdent)
1884 return CurrentIdent;
1889 SingleChoice = !CurrentIdent;
1901 getCombinedIdentFromCallUsesIn(OMPInformationCache::RuntimeFunctionInfo &RFI,
1903 bool SingleChoice =
true;
1904 Value *Ident =
nullptr;
1906 CallInst *CI = getCallIfRegularCall(U, &RFI);
1907 if (!CI || &
F != &Caller)
1910 true, SingleChoice);
1913 RFI.foreachUse(SCC, CombineIdentStruct);
1915 if (!Ident || !SingleChoice) {
1919 if (!OMPInfoCache.OMPBuilder.getInsertionPoint().isValid())
1920 OMPInfoCache.OMPBuilder.updateToLocation(
1921 {
F.getEntryBlock().begin(),
DebugLoc()});
1924 uint32_t SrcLocStrSize;
1926 OMPInfoCache.OMPBuilder.getOrCreateDefaultSrcLocStr(SrcLocStrSize);
1927 Ident = OMPInfoCache.OMPBuilder.getOrCreateIdent(Loc, SrcLocStrSize);
1934 bool deduplicateRuntimeCalls(
Function &
F,
1935 OMPInformationCache::RuntimeFunctionInfo &RFI,
1936 Value *ReplVal =
nullptr) {
1937 auto *UV = RFI.getUseVector(
F);
1938 if (!UV || UV->size() + (ReplVal !=
nullptr) < 2)
1942 dbgs() <<
TAG <<
"Deduplicate " << UV->size() <<
" uses of " << RFI.Name
1943 << (ReplVal ?
" with an existing value\n" :
"\n") <<
"\n");
1947 "Unexpected replacement value!");
1950 auto CanBeMoved = [
this](CallBase &CB) {
1956 for (
unsigned U = 1;
U < NumArgs; ++
U)
1964 OMPInfoCache.getAnalysisResultForFunction<DominatorTreeAnalysis>(
F);
1968 for (Use *U : *UV) {
1969 if (CallInst *CI = getCallIfRegularCall(*U, &RFI)) {
1974 if (!CanBeMoved(*CI))
1982 assert(IP &&
"Expected insertion point!");
1992 Value *Ident = getCombinedIdentFromCallUsesIn(RFI,
F,
2000 CallInst *CI = getCallIfRegularCall(U, &RFI);
2001 if (!CI || CI == ReplVal || &
F != &Caller)
2005 auto Remark = [&](OptimizationRemark
OR) {
2006 return OR <<
"OpenMP runtime call "
2007 <<
ore::NV(
"OpenMPOptRuntime", RFI.Name) <<
" deduplicated.";
2016 ++NumOpenMPRuntimeCallsDeduplicated;
2020 RFI.foreachUse(SCC, ReplaceAndDeleteCB);
2026 void collectGlobalThreadIdArguments(SmallSetVector<Value *, 16> >IdArgs) {
2033 auto CallArgOpIsGTId = [&](
Function &
F,
unsigned ArgNo, CallInst &RefCI) {
2034 if (!
F.hasLocalLinkage())
2036 for (Use &U :
F.uses()) {
2037 if (CallInst *CI = getCallIfRegularCall(U)) {
2039 if (CI == &RefCI || GTIdArgs.
count(ArgOp) ||
2040 getCallIfRegularCall(
2041 *ArgOp, &OMPInfoCache.RFIs[OMPRTL___kmpc_global_thread_num]))
2050 auto AddUserArgs = [&](
Value >Id) {
2051 for (Use &U : GTId.uses())
2055 if (CallArgOpIsGTId(*Callee,
U.getOperandNo(), *CI))
2060 OMPInformationCache::RuntimeFunctionInfo &GlobThreadNumRFI =
2061 OMPInfoCache.RFIs[OMPRTL___kmpc_global_thread_num];
2063 GlobThreadNumRFI.foreachUse(SCC, [&](Use &U,
Function &
F) {
2064 if (CallInst *CI = getCallIfRegularCall(U, &GlobThreadNumRFI))
2072 for (
unsigned U = 0;
U < GTIdArgs.
size(); ++
U)
2073 AddUserArgs(*GTIdArgs[U]);
2081 DenseMap<Function *, std::optional<Kernel>> UniqueKernelMap;
2087 Kernel getUniqueKernelFor(Instruction &
I) {
2088 return getUniqueKernelFor(*
I.getFunction());
2093 bool rewriteDeviceCodeStateMachine();
2098 bool removeSPMDParallelWrappers();
2114 template <
typename RemarkKind,
typename RemarkCallBack>
2115 void emitRemark(Instruction *
I, StringRef RemarkName,
2116 RemarkCallBack &&RemarkCB)
const {
2118 auto &ORE = OREGetter(
F);
2122 return RemarkCB(RemarkKind(
DEBUG_TYPE, RemarkName,
I))
2123 <<
" [" << RemarkName <<
"]";
2127 [&]() {
return RemarkCB(RemarkKind(
DEBUG_TYPE, RemarkName,
I)); });
2131 template <
typename RemarkKind,
typename RemarkCallBack>
2133 RemarkCallBack &&RemarkCB)
const {
2134 auto &ORE = OREGetter(
F);
2138 return RemarkCB(RemarkKind(
DEBUG_TYPE, RemarkName,
F))
2139 <<
" [" << RemarkName <<
"]";
2143 [&]() {
return RemarkCB(RemarkKind(
DEBUG_TYPE, RemarkName,
F)); });
2150 SmallVectorImpl<Function *> &SCC;
2154 CallGraphUpdater &CGUpdater;
2157 OptimizationRemarkGetter OREGetter;
2160 OMPInformationCache &OMPInfoCache;
2166 bool runAttributor(
bool IsModulePass) {
2170 registerAAs(IsModulePass);
2175 <<
" functions, result: " <<
Changed <<
".\n");
2177 if (
Changed == ChangeStatus::CHANGED)
2178 OMPInfoCache.invalidateAnalyses();
2180 return Changed == ChangeStatus::CHANGED;
2187 void registerAAs(
bool IsModulePass);
2192 static void registerAAsForFunction(Attributor &A,
const Function &
F);
2196 if (OMPInfoCache.CGSCC && !OMPInfoCache.CGSCC->empty() &&
2197 !OMPInfoCache.CGSCC->contains(&
F))
2202 std::optional<Kernel> &CachedKernel = UniqueKernelMap[&
F];
2204 return *CachedKernel;
2211 return *CachedKernel;
2214 CachedKernel =
nullptr;
2215 if (!
F.hasLocalLinkage()) {
2218 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
2219 return ORA <<
"Potentially unknown OpenMP target region caller.";
2227 auto GetUniqueKernelForUse = [&](
const Use &
U) ->
Kernel {
2230 if (
Cmp->isEquality())
2231 return getUniqueKernelFor(*Cmp);
2237 return getUniqueKernelFor(*CB);
2239 OMPInformationCache::RuntimeFunctionInfo &KernelParallelRFI =
2240 OMPInfoCache.RFIs[OMPRTL___kmpc_parallel_60];
2242 if (OpenMPOpt::getCallIfRegularCall(*
U.getUser(), &KernelParallelRFI))
2243 return getUniqueKernelFor(*CB);
2251 SmallPtrSet<Kernel, 2> PotentialKernels;
2252 OMPInformationCache::foreachUse(
F, [&](
const Use &U) {
2253 PotentialKernels.
insert(GetUniqueKernelForUse(U));
2257 if (PotentialKernels.
size() == 1)
2258 K = *PotentialKernels.
begin();
2261 UniqueKernelMap[&
F] =
K;
2266bool OpenMPOpt::rewriteDeviceCodeStateMachine() {
2267 OMPInformationCache::RuntimeFunctionInfo &KernelParallelRFI =
2268 OMPInfoCache.RFIs[OMPRTL___kmpc_parallel_60];
2271 if (!KernelParallelRFI)
2282 bool UnknownUse =
false;
2283 bool KernelParallelUse =
false;
2284 unsigned NumDirectCalls = 0;
2287 OMPInformationCache::foreachUse(*
F, [&](Use &U) {
2295 ToBeReplacedStateMachineUses.
push_back(&U);
2301 OpenMPOpt::getCallIfRegularCall(*
U.getUser(), &KernelParallelRFI);
2302 const unsigned int WrapperFunctionArgNo = 6;
2303 if (!KernelParallelUse && CI &&
2305 KernelParallelUse =
true;
2306 ToBeReplacedStateMachineUses.
push_back(&U);
2314 if (!KernelParallelUse)
2320 if (UnknownUse || NumDirectCalls != 1 ||
2321 ToBeReplacedStateMachineUses.
size() > 2) {
2322 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
2323 return ORA <<
"Parallel region is used in "
2324 << (UnknownUse ?
"unknown" :
"unexpected")
2325 <<
" ways. Will not attempt to rewrite the state machine.";
2335 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
2336 return ORA <<
"Parallel region is not called from a unique kernel. "
2337 "Will not attempt to rewrite the state machine.";
2349 Type *Int8Ty = Type::getInt8Ty(
M.getContext());
2351 auto *
ID =
new GlobalVariable(
2355 for (Use *U : ToBeReplacedStateMachineUses)
2357 ID,
U->get()->getType()));
2359 ++NumOpenMPParallelRegionsReplacedInGPUStateMachine;
2367bool OpenMPOpt::removeSPMDParallelWrappers() {
2369 if (OMPInfoCache.SPMDizedKernels.empty())
2372 OMPInformationCache::RuntimeFunctionInfo &KernelParallelRFI =
2373 OMPInfoCache.RFIs[OMPRTL___kmpc_parallel_60];
2374 if (!KernelParallelRFI || !KernelParallelRFI.Declaration)
2377 constexpr unsigned WrapperFunctionArgNo = 6;
2379 for (User *U : KernelParallelRFI.Declaration->
users()) {
2382 CI->
arg_size() <= WrapperFunctionArgNo)
2396 if (!K || !OMPInfoCache.SPMDizedKernels.contains(K))
2400 WrapperFunctionArgNo,
2409struct AAICVTracker :
public StateWrapper<BooleanState, AbstractAttribute> {
2410 using Base = StateWrapper<BooleanState, AbstractAttribute>;
2411 AAICVTracker(
const IRPosition &IRP, Attributor &
A) :
Base(IRP) {}
2414 bool isAssumedTracked()
const {
return getAssumed(); }
2417 bool isKnownTracked()
const {
return getAssumed(); }
2420 static AAICVTracker &createForPosition(
const IRPosition &IRP, Attributor &
A);
2424 const Instruction *
I,
2425 Attributor &
A)
const {
2426 return std::nullopt;
2432 virtual std::optional<Value *>
2440 StringRef
getName()
const override {
return "AAICVTracker"; }
2443 const char *getIdAddr()
const override {
return &ID; }
2446 static bool classof(
const AbstractAttribute *AA) {
2450 static const char ID;
2453struct AAICVTrackerFunction :
public AAICVTracker {
2454 AAICVTrackerFunction(
const IRPosition &IRP, Attributor &
A)
2455 : AAICVTracker(IRP,
A) {}
2458 const std::string getAsStr(Attributor *)
const override {
2459 return "ICVTrackerFunction";
2463 void trackStatistics()
const override {}
2467 return ChangeStatus::UNCHANGED;
2472 InternalControlVar::ICV___last>
2473 ICVReplacementValuesMap;
2480 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
2483 auto &SetterRFI = OMPInfoCache.RFIs[OMPInfoCache.ICVs[ICV].Setter];
2485 auto &ValuesMap = ICVReplacementValuesMap[ICV];
2487 CallInst *CI = OpenMPOpt::getCallIfRegularCall(U);
2493 if (ValuesMap.insert(std::make_pair(CI, CI->
getArgOperand(0))).second)
2494 HasChanged = ChangeStatus::CHANGED;
2500 std::optional<Value *> ReplVal = getValueForCall(
A,
I, ICV);
2501 if (ReplVal && ValuesMap.insert(std::make_pair(&
I, *ReplVal)).second)
2502 HasChanged = ChangeStatus::CHANGED;
2508 SetterRFI.foreachUse(TrackValues,
F);
2510 bool UsedAssumedInformation =
false;
2511 A.checkForAllInstructions(CallCheck, *
this, {Instruction::Call},
2512 UsedAssumedInformation,
2518 if (HasChanged == ChangeStatus::CHANGED)
2519 ValuesMap.try_emplace(Entry);
2527 std::optional<Value *> getValueForCall(Attributor &
A,
const Instruction &
I,
2531 if (!CB || CB->
hasFnAttr(
"no_openmp") ||
2534 return std::nullopt;
2536 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
2537 auto &GetterRFI = OMPInfoCache.RFIs[OMPInfoCache.ICVs[ICV].Getter];
2538 auto &SetterRFI = OMPInfoCache.RFIs[OMPInfoCache.ICVs[ICV].Setter];
2542 if (CalledFunction ==
nullptr)
2544 if (CalledFunction == GetterRFI.Declaration)
2545 return std::nullopt;
2546 if (CalledFunction == SetterRFI.Declaration) {
2547 if (ICVReplacementValuesMap[ICV].
count(&
I))
2548 return ICVReplacementValuesMap[ICV].lookup(&
I);
2557 const auto *ICVTrackingAA =
A.getAAFor<AAICVTracker>(
2560 if (ICVTrackingAA->isAssumedTracked()) {
2561 std::optional<Value *> URV =
2562 ICVTrackingAA->getUniqueReplacementValue(ICV);
2573 std::optional<Value *>
2575 return std::nullopt;
2580 const Instruction *
I,
2581 Attributor &
A)
const override {
2582 const auto &ValuesMap = ICVReplacementValuesMap[ICV];
2583 if (ValuesMap.count(
I))
2584 return ValuesMap.lookup(
I);
2587 SmallPtrSet<const Instruction *, 16> Visited;
2590 std::optional<Value *> ReplVal;
2592 while (!Worklist.
empty()) {
2594 if (!Visited.
insert(CurrInst).second)
2602 if (ValuesMap.count(CurrInst)) {
2603 std::optional<Value *> NewReplVal = ValuesMap.lookup(CurrInst);
2606 ReplVal = NewReplVal;
2612 if (ReplVal != NewReplVal)
2618 std::optional<Value *> NewReplVal = getValueForCall(
A, *CurrInst, ICV);
2624 ReplVal = NewReplVal;
2630 if (ReplVal != NewReplVal)
2635 if (CurrBB ==
I->getParent() && ReplVal)
2640 if (
const Instruction *Terminator = Pred->getTerminator())
2648struct AAICVTrackerFunctionReturned : AAICVTracker {
2649 AAICVTrackerFunctionReturned(
const IRPosition &IRP, Attributor &
A)
2650 : AAICVTracker(IRP,
A) {}
2653 const std::string getAsStr(Attributor *)
const override {
2654 return "ICVTrackerFunctionReturned";
2658 void trackStatistics()
const override {}
2662 return ChangeStatus::UNCHANGED;
2667 InternalControlVar::ICV___last>
2668 ICVReplacementValuesMap;
2671 std::optional<Value *>
2673 return ICVReplacementValuesMap[ICV];
2678 const auto *ICVTrackingAA =
A.getAAFor<AAICVTracker>(
2681 if (!ICVTrackingAA->isAssumedTracked())
2682 return indicatePessimisticFixpoint();
2685 std::optional<Value *> &ReplVal = ICVReplacementValuesMap[ICV];
2686 std::optional<Value *> UniqueICVValue;
2689 std::optional<Value *> NewReplVal =
2690 ICVTrackingAA->getReplacementValue(ICV, &
I,
A);
2693 if (UniqueICVValue && UniqueICVValue != NewReplVal)
2696 UniqueICVValue = NewReplVal;
2701 bool UsedAssumedInformation =
false;
2702 if (!
A.checkForAllInstructions(CheckReturnInst, *
this, {Instruction::Ret},
2703 UsedAssumedInformation,
2705 UniqueICVValue =
nullptr;
2707 if (UniqueICVValue == ReplVal)
2710 ReplVal = UniqueICVValue;
2711 Changed = ChangeStatus::CHANGED;
2718struct AAICVTrackerCallSite : AAICVTracker {
2719 AAICVTrackerCallSite(
const IRPosition &IRP, Attributor &
A)
2720 : AAICVTracker(IRP,
A) {}
2723 assert(getAnchorScope() &&
"Expected anchor function");
2727 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
2729 auto ICVInfo = OMPInfoCache.ICVs[ICV];
2730 auto &Getter = OMPInfoCache.RFIs[ICVInfo.Getter];
2731 if (Getter.Declaration == getAssociatedFunction()) {
2732 AssociatedICV = ICVInfo.Kind;
2738 indicatePessimisticFixpoint();
2742 if (!ReplVal || !*ReplVal)
2743 return ChangeStatus::UNCHANGED;
2746 A.deleteAfterManifest(*getCtxI());
2748 return ChangeStatus::CHANGED;
2752 const std::string getAsStr(Attributor *)
const override {
2753 return "ICVTrackerCallSite";
2757 void trackStatistics()
const override {}
2760 std::optional<Value *> ReplVal;
2763 const auto *ICVTrackingAA =
A.getAAFor<AAICVTracker>(
2767 if (!ICVTrackingAA->isAssumedTracked())
2768 return indicatePessimisticFixpoint();
2770 std::optional<Value *> NewReplVal =
2771 ICVTrackingAA->getReplacementValue(AssociatedICV, getCtxI(),
A);
2773 if (ReplVal == NewReplVal)
2774 return ChangeStatus::UNCHANGED;
2776 ReplVal = NewReplVal;
2777 return ChangeStatus::CHANGED;
2782 std::optional<Value *>
2788struct AAICVTrackerCallSiteReturned : AAICVTracker {
2789 AAICVTrackerCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
2790 : AAICVTracker(IRP,
A) {}
2793 const std::string getAsStr(Attributor *)
const override {
2794 return "ICVTrackerCallSiteReturned";
2798 void trackStatistics()
const override {}
2802 return ChangeStatus::UNCHANGED;
2807 InternalControlVar::ICV___last>
2808 ICVReplacementValuesMap;
2812 std::optional<Value *>
2814 return ICVReplacementValuesMap[ICV];
2819 const auto *ICVTrackingAA =
A.getAAFor<AAICVTracker>(
2821 DepClassTy::REQUIRED);
2824 if (!ICVTrackingAA->isAssumedTracked())
2825 return indicatePessimisticFixpoint();
2828 std::optional<Value *> &ReplVal = ICVReplacementValuesMap[ICV];
2829 std::optional<Value *> NewReplVal =
2830 ICVTrackingAA->getUniqueReplacementValue(ICV);
2832 if (ReplVal == NewReplVal)
2835 ReplVal = NewReplVal;
2836 Changed = ChangeStatus::CHANGED;
2844static bool hasFunctionEndAsUniqueSuccessor(
const BasicBlock *BB) {
2850 return hasFunctionEndAsUniqueSuccessor(
Successor);
2853struct AAExecutionDomainFunction :
public AAExecutionDomain {
2854 AAExecutionDomainFunction(
const IRPosition &IRP, Attributor &
A)
2855 : AAExecutionDomain(IRP,
A) {}
2857 ~AAExecutionDomainFunction()
override {
delete RPOT; }
2861 assert(
F &&
"Expected anchor function");
2862 RPOT =
new ReversePostOrderTraversal<Function *>(
F);
2865 const std::string getAsStr(Attributor *)
const override {
2866 unsigned TotalBlocks = 0, InitialThreadBlocks = 0, AlignedBlocks = 0;
2867 for (
auto &It : BEDMap) {
2871 InitialThreadBlocks += It.getSecond().IsExecutedByInitialThreadOnly;
2872 AlignedBlocks += It.getSecond().IsReachedFromAlignedBarrierOnly &&
2873 It.getSecond().IsReachingAlignedBarrierOnly;
2875 return "[AAExecutionDomain] " + std::to_string(InitialThreadBlocks) +
"/" +
2876 std::to_string(AlignedBlocks) +
" of " +
2877 std::to_string(TotalBlocks) +
2878 " executed by initial thread / aligned";
2882 void trackStatistics()
const override {}
2886 for (
const BasicBlock &BB : *getAnchorScope()) {
2887 if (!isExecutedByInitialThreadOnly(BB))
2889 dbgs() <<
TAG <<
" Basic block @" << getAnchorScope()->getName() <<
" "
2890 << BB.
getName() <<
" is executed by a single thread.\n";
2899 SmallPtrSet<CallBase *, 16> DeletedBarriers;
2900 auto HandleAlignedBarrier = [&](CallBase *CB) {
2901 const ExecutionDomainTy &ED = CB ? CEDMap[{CB, PRE}] : BEDMap[
nullptr];
2902 if (!ED.IsReachedFromAlignedBarrierOnly ||
2903 ED.EncounteredNonLocalSideEffect)
2905 if (!ED.EncounteredAssumes.empty() && !
A.isModulePass())
2916 DeletedBarriers.
insert(CB);
2917 A.deleteAfterManifest(*CB);
2918 ++NumBarriersEliminated;
2919 Changed = ChangeStatus::CHANGED;
2920 }
else if (!ED.AlignedBarriers.empty()) {
2921 Changed = ChangeStatus::CHANGED;
2923 ED.AlignedBarriers.end());
2924 SmallSetVector<CallBase *, 16> Visited;
2925 while (!Worklist.
empty()) {
2927 if (!Visited.
insert(LastCB))
2931 if (!hasFunctionEndAsUniqueSuccessor(LastCB->
getParent()))
2933 if (!DeletedBarriers.
count(LastCB)) {
2934 ++NumBarriersEliminated;
2935 A.deleteAfterManifest(*LastCB);
2941 const ExecutionDomainTy &LastED = CEDMap[{LastCB, PRE}];
2942 Worklist.
append(LastED.AlignedBarriers.begin(),
2943 LastED.AlignedBarriers.end());
2949 if (!ED.EncounteredAssumes.empty() && (CB || !ED.AlignedBarriers.empty()))
2950 for (
auto *AssumeCB : ED.EncounteredAssumes)
2951 A.deleteAfterManifest(*AssumeCB);
2954 for (
auto *CB : AlignedBarriers)
2955 HandleAlignedBarrier(CB);
2959 HandleAlignedBarrier(
nullptr);
2964 bool isNoOpFence(
const FenceInst &FI)
const override {
2965 return getState().isValidState() && !NonNoOpFences.count(&FI);
2971 mergeInPredecessorBarriersAndAssumptions(Attributor &
A, ExecutionDomainTy &ED,
2972 const ExecutionDomainTy &PredED);
2977 bool mergeInPredecessor(Attributor &
A, ExecutionDomainTy &ED,
2978 const ExecutionDomainTy &PredED,
2979 bool InitialEdgeOnly =
false);
2982 bool handleCallees(Attributor &
A, ExecutionDomainTy &EntryBBED);
2989 bool isExecutedByInitialThreadOnly(
const BasicBlock &BB)
const override {
2990 if (!isValidState())
2992 assert(BB.
getParent() == getAnchorScope() &&
"Block is out of scope!");
2993 return BEDMap.lookup(&BB).IsExecutedByInitialThreadOnly;
2996 bool isExecutedInAlignedRegion(Attributor &
A,
2997 const Instruction &
I)
const override {
2998 assert(
I.getFunction() == getAnchorScope() &&
2999 "Instruction is out of scope!");
3000 if (!isValidState())
3003 bool ForwardIsOk =
true;
3012 if (CB != &
I && AlignedBarriers.contains(
const_cast<CallBase *
>(CB)))
3014 const auto &It = CEDMap.find({CB, PRE});
3015 if (It == CEDMap.end())
3017 if (!It->getSecond().IsReachingAlignedBarrierOnly)
3018 ForwardIsOk =
false;
3022 if (!CurI && !BEDMap.lookup(
I.getParent()).IsReachingAlignedBarrierOnly)
3023 ForwardIsOk =
false;
3031 if (CB != &
I && AlignedBarriers.contains(
const_cast<CallBase *
>(CB)))
3033 const auto &It = CEDMap.find({CB, POST});
3034 if (It == CEDMap.end())
3036 if (It->getSecond().IsReachedFromAlignedBarrierOnly)
3049 return BEDMap.lookup(
nullptr).IsReachedFromAlignedBarrierOnly;
3051 return BEDMap.lookup(PredBB).IsReachedFromAlignedBarrierOnly;
3061 ExecutionDomainTy getExecutionDomain(
const BasicBlock &BB)
const override {
3063 "No request should be made against an invalid state!");
3064 return BEDMap.lookup(&BB);
3066 std::pair<ExecutionDomainTy, ExecutionDomainTy>
3067 getExecutionDomain(
const CallBase &CB)
const override {
3069 "No request should be made against an invalid state!");
3070 return {CEDMap.lookup({&CB, PRE}), CEDMap.lookup({&CB, POST})};
3072 ExecutionDomainTy getFunctionExecutionDomain()
const override {
3074 "No request should be made against an invalid state!");
3075 return InterProceduralED;
3081 static bool isInitialThreadOnlyEdge(Attributor &
A, CondBrInst *
Edge,
3082 BasicBlock &SuccessorBB) {
3085 if (
Edge->getSuccessor(0) != &SuccessorBB)
3089 if (!Cmp || !
Cmp->isTrueWhenEqual() || !
Cmp->isEquality())
3097 if (
C->isAllOnesValue()) {
3099 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
3100 auto &RFI = OMPInfoCache.RFIs[OMPRTL___kmpc_target_init];
3101 CB = CB ? OpenMPOpt::getCallIfRegularCall(*CB, &RFI) : nullptr;
3104 ConstantStruct *KernelEnvC =
3106 ConstantInt *ExecModeC =
3107 KernelInfo::getExecModeFromKernelEnvironment(KernelEnvC);
3114 if (
II->getIntrinsicID() == Intrinsic::nvvm_read_ptx_sreg_tid_x)
3119 if (
II->getIntrinsicID() == Intrinsic::amdgcn_workitem_id_x)
3127 ExecutionDomainTy InterProceduralED;
3131 DenseMap<const BasicBlock *, ExecutionDomainTy> BEDMap;
3132 DenseMap<PointerIntPair<const CallBase *, 1, Direction>, ExecutionDomainTy>
3134 SmallSetVector<CallBase *, 16> AlignedBarriers;
3136 ReversePostOrderTraversal<Function *> *RPOT =
nullptr;
3139 static bool setAndRecord(
bool &R,
bool V) {
3147 SmallPtrSet<const FenceInst *, 8> NonNoOpFences;
3150void AAExecutionDomainFunction::mergeInPredecessorBarriersAndAssumptions(
3151 Attributor &
A, ExecutionDomainTy &ED,
const ExecutionDomainTy &PredED) {
3152 for (
auto *EA : PredED.EncounteredAssumes)
3153 ED.addAssumeInst(
A, *EA);
3155 for (
auto *AB : PredED.AlignedBarriers)
3156 ED.addAlignedBarrier(
A, *AB);
3159bool AAExecutionDomainFunction::mergeInPredecessor(
3160 Attributor &
A, ExecutionDomainTy &ED,
const ExecutionDomainTy &PredED,
3161 bool InitialEdgeOnly) {
3165 setAndRecord(ED.IsExecutedByInitialThreadOnly,
3166 InitialEdgeOnly || (PredED.IsExecutedByInitialThreadOnly &&
3167 ED.IsExecutedByInitialThreadOnly));
3169 Changed |= setAndRecord(ED.IsReachedFromAlignedBarrierOnly,
3170 ED.IsReachedFromAlignedBarrierOnly &&
3171 PredED.IsReachedFromAlignedBarrierOnly);
3172 Changed |= setAndRecord(ED.EncounteredNonLocalSideEffect,
3173 ED.EncounteredNonLocalSideEffect |
3174 PredED.EncounteredNonLocalSideEffect);
3176 if (ED.IsReachedFromAlignedBarrierOnly)
3177 mergeInPredecessorBarriersAndAssumptions(
A, ED, PredED);
3179 ED.clearAssumeInstAndAlignedBarriers();
3183bool AAExecutionDomainFunction::handleCallees(Attributor &
A,
3184 ExecutionDomainTy &EntryBBED) {
3186 auto PredForCallSite = [&](AbstractCallSite ACS) {
3187 const auto *EDAA =
A.getAAFor<AAExecutionDomain>(
3189 DepClassTy::OPTIONAL);
3190 if (!EDAA || !EDAA->getState().isValidState())
3193 EDAA->getExecutionDomain(*
cast<CallBase>(ACS.getInstruction())));
3197 ExecutionDomainTy ExitED;
3198 bool AllCallSitesKnown;
3199 if (
A.checkForAllCallSites(PredForCallSite, *
this,
3201 AllCallSitesKnown)) {
3202 for (
const auto &[CSInED, CSOutED] : CallSiteEDs) {
3203 mergeInPredecessor(
A, EntryBBED, CSInED);
3204 ExitED.IsReachingAlignedBarrierOnly &=
3205 CSOutED.IsReachingAlignedBarrierOnly;
3212 EntryBBED.IsExecutedByInitialThreadOnly =
false;
3213 EntryBBED.IsReachedFromAlignedBarrierOnly =
true;
3214 EntryBBED.EncounteredNonLocalSideEffect =
false;
3215 ExitED.IsReachingAlignedBarrierOnly =
false;
3217 EntryBBED.IsExecutedByInitialThreadOnly =
false;
3218 EntryBBED.IsReachedFromAlignedBarrierOnly =
false;
3219 EntryBBED.EncounteredNonLocalSideEffect =
true;
3220 ExitED.IsReachingAlignedBarrierOnly =
false;
3225 auto &FnED = BEDMap[
nullptr];
3226 Changed |= setAndRecord(FnED.IsReachedFromAlignedBarrierOnly,
3227 FnED.IsReachedFromAlignedBarrierOnly &
3228 EntryBBED.IsReachedFromAlignedBarrierOnly);
3229 Changed |= setAndRecord(FnED.IsReachingAlignedBarrierOnly,
3230 FnED.IsReachingAlignedBarrierOnly &
3231 ExitED.IsReachingAlignedBarrierOnly);
3232 Changed |= setAndRecord(FnED.IsExecutedByInitialThreadOnly,
3233 EntryBBED.IsExecutedByInitialThreadOnly);
3237ChangeStatus AAExecutionDomainFunction::updateImpl(Attributor &
A) {
3244 auto HandleAlignedBarrier = [&](CallBase &CB, ExecutionDomainTy &ED) {
3245 Changed |= AlignedBarriers.insert(&CB);
3247 auto &CallInED = CEDMap[{&CB, PRE}];
3248 Changed |= mergeInPredecessor(
A, CallInED, ED);
3249 CallInED.IsReachingAlignedBarrierOnly =
true;
3251 ED.EncounteredNonLocalSideEffect =
false;
3252 ED.IsReachedFromAlignedBarrierOnly =
true;
3254 ED.clearAssumeInstAndAlignedBarriers();
3255 ED.addAlignedBarrier(
A, CB);
3256 auto &CallOutED = CEDMap[{&CB, POST}];
3257 Changed |= mergeInPredecessor(
A, CallOutED, ED);
3261 A.getAAFor<AAIsDead>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
3267 SmallVector<Instruction *> SyncInstWorklist;
3268 for (
auto &RIt : *RPOT) {
3271 bool IsEntryBB = &BB == &EntryBB;
3274 bool AlignedBarrierLastInBlock = IsEntryBB && IsKernel;
3275 bool IsExplicitlyAligned = IsEntryBB && IsKernel;
3276 ExecutionDomainTy ED;
3283 if (LivenessAA && LivenessAA->isAssumedDead(&BB))
3287 if (LivenessAA && LivenessAA->isEdgeDead(PredBB, &BB))
3289 bool InitialEdgeOnly = isInitialThreadOnlyEdge(
3291 mergeInPredecessor(
A, ED, BEDMap[PredBB], InitialEdgeOnly);
3297 for (Instruction &
I : BB) {
3298 bool UsedAssumedInformation;
3299 if (
A.isAssumedDead(
I, *
this, LivenessAA, UsedAssumedInformation,
3300 false, DepClassTy::OPTIONAL,
3308 ED.addAssumeInst(
A, *AI);
3312 if (
II->isAssumeLikeIntrinsic())
3317 if (!ED.EncounteredNonLocalSideEffect) {
3319 if (ED.IsReachedFromAlignedBarrierOnly)
3324 case AtomicOrdering::NotAtomic:
3326 case AtomicOrdering::Unordered:
3328 case AtomicOrdering::Monotonic:
3330 case AtomicOrdering::Acquire:
3332 case AtomicOrdering::Release:
3334 case AtomicOrdering::AcquireRelease:
3336 case AtomicOrdering::SequentiallyConsistent:
3340 NonNoOpFences.insert(FI);
3345 bool IsAlignedBarrier =
3349 AlignedBarrierLastInBlock &= IsNoSync;
3350 IsExplicitlyAligned &= IsNoSync;
3356 if (IsAlignedBarrier) {
3357 HandleAlignedBarrier(*CB, ED);
3358 AlignedBarrierLastInBlock =
true;
3359 IsExplicitlyAligned =
true;
3365 if (!ED.EncounteredNonLocalSideEffect &&
3367 ED.EncounteredNonLocalSideEffect =
true;
3369 ED.IsReachedFromAlignedBarrierOnly =
false;
3377 auto &CallInED = CEDMap[{CB, PRE}];
3378 Changed |= mergeInPredecessor(
A, CallInED, ED);
3384 if (!IsNoSync && Callee && !
Callee->isDeclaration()) {
3385 const auto *EDAA =
A.getAAFor<AAExecutionDomain>(
3387 if (EDAA && EDAA->getState().isValidState()) {
3388 const auto &CalleeED = EDAA->getFunctionExecutionDomain();
3389 ED.IsReachedFromAlignedBarrierOnly =
3390 CalleeED.IsReachedFromAlignedBarrierOnly;
3391 AlignedBarrierLastInBlock = ED.IsReachedFromAlignedBarrierOnly;
3392 if (IsNoSync || !CalleeED.IsReachedFromAlignedBarrierOnly)
3393 ED.EncounteredNonLocalSideEffect |=
3394 CalleeED.EncounteredNonLocalSideEffect;
3396 ED.EncounteredNonLocalSideEffect =
3397 CalleeED.EncounteredNonLocalSideEffect;
3398 if (!CalleeED.IsReachingAlignedBarrierOnly) {
3400 setAndRecord(CallInED.IsReachingAlignedBarrierOnly,
false);
3403 if (CalleeED.IsReachedFromAlignedBarrierOnly)
3404 mergeInPredecessorBarriersAndAssumptions(
A, ED, CalleeED);
3405 auto &CallOutED = CEDMap[{CB, POST}];
3406 Changed |= mergeInPredecessor(
A, CallOutED, ED);
3411 ED.IsReachedFromAlignedBarrierOnly =
false;
3412 Changed |= setAndRecord(CallInED.IsReachingAlignedBarrierOnly,
false);
3415 AlignedBarrierLastInBlock &= ED.IsReachedFromAlignedBarrierOnly;
3417 auto &CallOutED = CEDMap[{CB, POST}];
3418 Changed |= mergeInPredecessor(
A, CallOutED, ED);
3421 if (!
I.mayHaveSideEffects() && !
I.mayReadFromMemory())
3427 const auto *MemAA =
A.getAAFor<AAMemoryLocation>(
3435 if (MemAA && MemAA->getState().isValidState() &&
3436 MemAA->checkForAllAccessesToMemoryKind(
3441 auto &InfoCache =
A.getInfoCache();
3442 if (!
I.mayHaveSideEffects() && InfoCache.isOnlyUsedByAssume(
I))
3446 if (LI->hasMetadata(LLVMContext::MD_invariant_load))
3449 if (!ED.EncounteredNonLocalSideEffect &&
3451 ED.EncounteredNonLocalSideEffect =
true;
3454 bool IsEndAndNotReachingAlignedBarriersOnly =
false;
3456 !BB.getTerminator()->getNumSuccessors()) {
3458 Changed |= mergeInPredecessor(
A, InterProceduralED, ED);
3460 auto &FnED = BEDMap[
nullptr];
3461 if (IsKernel && !IsExplicitlyAligned)
3462 FnED.IsReachingAlignedBarrierOnly =
false;
3463 Changed |= mergeInPredecessor(
A, FnED, ED);
3465 if (!FnED.IsReachingAlignedBarrierOnly) {
3466 IsEndAndNotReachingAlignedBarriersOnly =
true;
3467 SyncInstWorklist.
push_back(BB.getTerminator());
3468 auto &BBED = BEDMap[&BB];
3469 Changed |= setAndRecord(BBED.IsReachingAlignedBarrierOnly,
false);
3473 ExecutionDomainTy &StoredED = BEDMap[&BB];
3474 ED.IsReachingAlignedBarrierOnly = StoredED.IsReachingAlignedBarrierOnly &&
3475 !IsEndAndNotReachingAlignedBarriersOnly;
3481 if (ED.IsExecutedByInitialThreadOnly !=
3482 StoredED.IsExecutedByInitialThreadOnly ||
3483 ED.IsReachedFromAlignedBarrierOnly !=
3484 StoredED.IsReachedFromAlignedBarrierOnly ||
3485 ED.EncounteredNonLocalSideEffect !=
3486 StoredED.EncounteredNonLocalSideEffect)
3490 StoredED = std::move(ED);
3495 SmallSetVector<BasicBlock *, 16> Visited;
3496 while (!SyncInstWorklist.
empty()) {
3499 bool HitAlignedBarrierOrKnownEnd =
false;
3504 auto &CallOutED = CEDMap[{CB, POST}];
3505 Changed |= setAndRecord(CallOutED.IsReachingAlignedBarrierOnly,
false);
3506 auto &CallInED = CEDMap[{CB, PRE}];
3507 HitAlignedBarrierOrKnownEnd =
3508 AlignedBarriers.count(CB) || !CallInED.IsReachingAlignedBarrierOnly;
3509 if (HitAlignedBarrierOrKnownEnd)
3511 Changed |= setAndRecord(CallInED.IsReachingAlignedBarrierOnly,
false);
3513 if (HitAlignedBarrierOrKnownEnd)
3517 if (LivenessAA && LivenessAA->isEdgeDead(PredBB, SyncBB))
3519 if (!Visited.
insert(PredBB))
3521 auto &PredED = BEDMap[PredBB];
3522 if (setAndRecord(PredED.IsReachingAlignedBarrierOnly,
false)) {
3524 SyncInstWorklist.
push_back(PredBB->getTerminator());
3527 if (SyncBB != &EntryBB)
3530 setAndRecord(InterProceduralED.IsReachingAlignedBarrierOnly,
false);
3533 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
3538struct AAHeapToShared :
public StateWrapper<BooleanState, AbstractAttribute> {
3539 using Base = StateWrapper<BooleanState, AbstractAttribute>;
3540 AAHeapToShared(
const IRPosition &IRP, Attributor &
A) :
Base(IRP) {}
3543 static AAHeapToShared &createForPosition(
const IRPosition &IRP,
3547 virtual bool isAssumedHeapToShared(CallBase &CB)
const = 0;
3551 virtual bool isAssumedHeapToSharedRemovedFree(CallBase &CB)
const = 0;
3554 StringRef
getName()
const override {
return "AAHeapToShared"; }
3557 const char *getIdAddr()
const override {
return &ID; }
3561 static bool classof(
const AbstractAttribute *AA) {
3566 static const char ID;
3569struct AAHeapToSharedFunction :
public AAHeapToShared {
3570 AAHeapToSharedFunction(
const IRPosition &IRP, Attributor &
A)
3571 : AAHeapToShared(IRP,
A) {}
3573 const std::string getAsStr(Attributor *)
const override {
3574 return "[AAHeapToShared] " + std::to_string(MallocCalls.size()) +
3575 " malloc calls eligible.";
3579 void trackStatistics()
const override {}
3583 void findPotentialRemovedFreeCalls(Attributor &
A) {
3584 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
3585 auto &FreeRFI = OMPInfoCache.RFIs[OMPRTL___kmpc_free_shared];
3587 PotentialRemovedFreeCalls.clear();
3589 for (CallBase *CB : MallocCalls) {
3591 for (
auto *U : CB->
users()) {
3593 if (
C &&
C->getCalledFunction() == FreeRFI.Declaration)
3597 if (FreeCalls.
size() != 1)
3600 PotentialRemovedFreeCalls.insert(FreeCalls.
front());
3606 indicatePessimisticFixpoint();
3610 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
3611 auto &RFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
3612 if (!RFI.Declaration)
3616 [](
const IRPosition &,
const AbstractAttribute *,
3617 bool &) -> std::optional<Value *> {
return nullptr; };
3620 const OMPInformationCache::RuntimeFunctionInfo::UseVector *
Uses =
3621 RFI.getUseVector(*
F);
3625 for (Use *U : *
Uses)
3627 MallocCalls.insert(CB);
3632 findPotentialRemovedFreeCalls(
A);
3635 bool isAssumedHeapToShared(CallBase &CB)
const override {
3636 return isValidState() && MallocCalls.count(&CB);
3639 bool isAssumedHeapToSharedRemovedFree(CallBase &CB)
const override {
3640 return isValidState() && PotentialRemovedFreeCalls.count(&CB);
3644 if (MallocCalls.empty())
3645 return ChangeStatus::UNCHANGED;
3647 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
3648 auto &FreeCall = OMPInfoCache.RFIs[OMPRTL___kmpc_free_shared];
3652 DepClassTy::OPTIONAL);
3655 for (CallBase *CB : MallocCalls) {
3657 if (HS &&
HS->isAssumedHeapToStack(*CB))
3662 for (
auto *U : CB->
users()) {
3664 if (
C &&
C->getCalledFunction() == FreeCall.Declaration)
3667 if (FreeCalls.
size() != 1)
3674 <<
" with shared memory."
3675 <<
" Shared memory usage is limited to "
3681 <<
" with " << AllocSize->getZExtValue()
3682 <<
" bytes of shared memory\n");
3687 Type *Int8Ty = Type::getInt8Ty(
M->getContext());
3688 Type *Int8ArrTy = ArrayType::get(Int8Ty, AllocSize->getZExtValue());
3689 auto *SharedMem =
new GlobalVariable(
3693 static_cast<unsigned>(AddressSpace::Shared));
3695 SharedMem, PointerType::getUnqual(
M->getContext()));
3697 auto Remark = [&](OptimizationRemark
OR) {
3698 return OR <<
"Replaced globalized variable with "
3699 <<
ore::NV(
"SharedMemory", AllocSize->getZExtValue())
3700 << (AllocSize->isOne() ?
" byte " :
" bytes ")
3701 <<
"of shared memory.";
3703 A.emitRemark<OptimizationRemark>(CB,
"OMP111",
Remark);
3705 MaybeAlign
Alignment = CB->getRetAlign();
3707 "HeapToShared on allocation without alignment attribute");
3711 A.deleteAfterManifest(*CB);
3712 A.deleteAfterManifest(*FreeCalls.
front());
3714 SharedMemoryUsed += AllocSize->getZExtValue();
3715 NumBytesMovedToSharedMemory = SharedMemoryUsed;
3716 Changed = ChangeStatus::CHANGED;
3723 if (MallocCalls.empty())
3724 return indicatePessimisticFixpoint();
3725 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
3726 auto &RFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
3727 if (!RFI.Declaration)
3728 return ChangeStatus::UNCHANGED;
3732 auto NumMallocCalls = MallocCalls.size();
3735 for (User *U : RFI.Declaration->
users()) {
3737 if (CB->getCaller() !=
F)
3739 if (!MallocCalls.count(CB))
3742 MallocCalls.remove(CB);
3745 const auto *ED =
A.getAAFor<AAExecutionDomain>(
3747 if (!ED || !ED->isExecutedByInitialThreadOnly(*CB))
3748 MallocCalls.remove(CB);
3752 findPotentialRemovedFreeCalls(
A);
3754 if (NumMallocCalls != MallocCalls.size())
3755 return ChangeStatus::CHANGED;
3757 return ChangeStatus::UNCHANGED;
3761 SmallSetVector<CallBase *, 4> MallocCalls;
3763 SmallPtrSet<CallBase *, 4> PotentialRemovedFreeCalls;
3765 unsigned SharedMemoryUsed = 0;
3768struct AAKernelInfo :
public StateWrapper<KernelInfoState, AbstractAttribute> {
3769 using Base = StateWrapper<KernelInfoState, AbstractAttribute>;
3770 AAKernelInfo(
const IRPosition &IRP, Attributor &
A) :
Base(IRP) {}
3774 static bool requiresCalleeForCallBase() {
return false; }
3777 void trackStatistics()
const override {}
3780 const std::string getAsStr(Attributor *)
const override {
3781 if (!isValidState())
3783 return std::string(SPMDCompatibilityTracker.isAssumed() ?
"SPMD"
3785 std::string(SPMDCompatibilityTracker.isAtFixpoint() ?
" [FIX]"
3787 std::string(
" #PRs: ") +
3788 (ReachedKnownParallelRegions.isValidState()
3789 ? std::to_string(ReachedKnownParallelRegions.size())
3791 ", #Unknown PRs: " +
3792 (ReachedUnknownParallelRegions.isValidState()
3793 ? std::to_string(ReachedUnknownParallelRegions.size())
3795 ", #Reaching Kernels: " +
3796 (ReachingKernelEntries.isValidState()
3797 ? std::to_string(ReachingKernelEntries.size())
3800 (ParallelLevels.isValidState()
3801 ? std::to_string(ParallelLevels.size())
3803 ", NestedPar: " + (NestedParallelism ?
"yes" :
"no");
3807 static AAKernelInfo &createForPosition(
const IRPosition &IRP, Attributor &
A);
3810 StringRef
getName()
const override {
return "AAKernelInfo"; }
3813 const char *getIdAddr()
const override {
return &ID; }
3816 static bool classof(
const AbstractAttribute *AA) {
3820 static const char ID;
3825struct AAKernelInfoFunction : AAKernelInfo {
3826 AAKernelInfoFunction(
const IRPosition &IRP, Attributor &
A)
3827 : AAKernelInfo(IRP,
A) {}
3829 SmallPtrSet<Instruction *, 4> GuardedInstructions;
3831 SmallPtrSetImpl<Instruction *> &getGuardedInstructions() {
3832 return GuardedInstructions;
3835 void setConfigurationOfKernelEnvironment(ConstantStruct *ConfigC) {
3837 KernelEnvC, ConfigC, {KernelInfo::ConfigurationIdx});
3838 assert(NewKernelEnvC &&
"Failed to create new kernel environment");
3842#define KERNEL_ENVIRONMENT_CONFIGURATION_SETTER(MEMBER) \
3843 void set##MEMBER##OfKernelEnvironment(ConstantInt *NewVal) { \
3844 ConstantStruct *ConfigC = \
3845 KernelInfo::getConfigurationFromKernelEnvironment(KernelEnvC); \
3846 Constant *NewConfigC = ConstantFoldInsertValueInstruction( \
3847 ConfigC, NewVal, {KernelInfo::MEMBER##Idx}); \
3848 assert(NewConfigC && "Failed to create new configuration environment"); \
3849 setConfigurationOfKernelEnvironment(cast<ConstantStruct>(NewConfigC)); \
3860#undef KERNEL_ENVIRONMENT_CONFIGURATION_SETTER
3867 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
3871 OMPInformationCache::RuntimeFunctionInfo &InitRFI =
3872 OMPInfoCache.RFIs[OMPRTL___kmpc_target_init];
3873 OMPInformationCache::RuntimeFunctionInfo &DeinitRFI =
3874 OMPInfoCache.RFIs[OMPRTL___kmpc_target_deinit];
3878 auto StoreCallBase = [](
Use &U,
3879 OMPInformationCache::RuntimeFunctionInfo &RFI,
3881 CallBase *CB = OpenMPOpt::getCallIfRegularCall(U, &RFI);
3883 "Unexpected use of __kmpc_target_init or __kmpc_target_deinit!");
3885 "Multiple uses of __kmpc_target_init or __kmpc_target_deinit!");
3891 StoreCallBase(U, InitRFI, KernelInitCB);
3895 DeinitRFI.foreachUse(
3897 StoreCallBase(U, DeinitRFI, KernelDeinitCB);
3903 if (!KernelInitCB || !KernelDeinitCB)
3907 ReachingKernelEntries.insert(Fn);
3908 IsKernelEntry =
true;
3916 KernelConfigurationSimplifyCB =
3918 bool &UsedAssumedInformation) -> std::optional<Constant *> {
3919 if (!isAtFixpoint()) {
3922 UsedAssumedInformation =
true;
3928 A.registerGlobalVariableSimplificationCallback(
3929 *KernelEnvGV, KernelConfigurationSimplifyCB);
3932 bool CanChangeToSPMD = OMPInfoCache.runtimeFnsAvailable(
3933 {OMPRTL___kmpc_get_hardware_thread_id_in_block,
3934 OMPRTL___kmpc_barrier_simple_spmd});
3938 KernelInfo::getExecModeFromKernelEnvironment(KernelEnvC);
3943 SPMDCompatibilityTracker.indicateOptimisticFixpoint();
3947 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
3949 setExecModeOfKernelEnvironment(AssumedExecModeC);
3956 setMinThreadsOfKernelEnvironment(ConstantInt::get(Int32Ty, MinThreads));
3958 setMaxThreadsOfKernelEnvironment(ConstantInt::get(Int32Ty,
MaxThreads));
3959 auto [MinTeams, MaxTeams] =
3962 setMinTeamsOfKernelEnvironment(ConstantInt::get(Int32Ty, MinTeams));
3964 setMaxTeamsOfKernelEnvironment(ConstantInt::get(Int32Ty, MaxTeams));
3967 KernelInfo::getMayUseNestedParallelismFromKernelEnvironment(KernelEnvC);
3968 ConstantInt *AssumedMayUseNestedParallelismC = ConstantInt::get(
3970 setMayUseNestedParallelismOfKernelEnvironment(
3971 AssumedMayUseNestedParallelismC);
3975 KernelInfo::getUseGenericStateMachineFromKernelEnvironment(
3978 ConstantInt::get(UseGenericStateMachineC->
getIntegerType(),
false);
3979 setUseGenericStateMachineOfKernelEnvironment(
3980 AssumedUseGenericStateMachineC);
3986 if (!OMPInfoCache.RFIs[RFKind].Declaration)
3988 A.registerVirtualUseCallback(*OMPInfoCache.RFIs[RFKind].Declaration, CB);
3992 auto AddDependence = [](
Attributor &
A,
const AAKernelInfo *KI,
4008 if (SPMDCompatibilityTracker.isValidState())
4009 return AddDependence(
A,
this, QueryingAA);
4011 if (!ReachedKnownParallelRegions.isValidState())
4012 return AddDependence(
A,
this, QueryingAA);
4018 RegisterVirtualUse(OMPRTL___kmpc_get_max_team_threads,
4019 CustomStateMachineUseCB);
4020 RegisterVirtualUse(OMPRTL___kmpc_barrier_simple_generic,
4021 CustomStateMachineUseCB);
4022 RegisterVirtualUse(OMPRTL___kmpc_kernel_parallel,
4023 CustomStateMachineUseCB);
4024 RegisterVirtualUse(OMPRTL___kmpc_kernel_end_parallel,
4025 CustomStateMachineUseCB);
4029 if (SPMDCompatibilityTracker.isAtFixpoint())
4036 if (!SPMDCompatibilityTracker.isValidState())
4037 return AddDependence(
A,
this, QueryingAA);
4040 RegisterVirtualUse(OMPRTL___kmpc_get_hardware_thread_id_in_block,
4049 if (!SPMDCompatibilityTracker.isValidState())
4050 return AddDependence(
A,
this, QueryingAA);
4051 if (SPMDCompatibilityTracker.empty())
4052 return AddDependence(
A,
this, QueryingAA);
4053 if (!mayContainParallelRegion())
4054 return AddDependence(
A,
this, QueryingAA);
4057 RegisterVirtualUse(OMPRTL___kmpc_barrier_simple_spmd, SPMDBarrierUseCB);
4061 static std::string sanitizeForGlobalName(std::string S) {
4065 return !((C >=
'a' && C <=
'z') || (C >=
'A' && C <=
'Z') ||
4066 (C >=
'0' && C <=
'9') || C ==
'_');
4077 if (!KernelInitCB || !KernelDeinitCB)
4078 return ChangeStatus::UNCHANGED;
4082 bool HasBuiltStateMachine =
true;
4083 if (!changeToSPMDMode(
A,
Changed)) {
4085 HasBuiltStateMachine = buildCustomStateMachine(
A,
Changed);
4087 HasBuiltStateMachine =
false;
4091 ConstantStruct *ExistingKernelEnvC =
4093 ConstantInt *OldUseGenericStateMachineVal =
4094 KernelInfo::getUseGenericStateMachineFromKernelEnvironment(
4095 ExistingKernelEnvC);
4096 if (!HasBuiltStateMachine)
4097 setUseGenericStateMachineOfKernelEnvironment(
4098 OldUseGenericStateMachineVal);
4101 GlobalVariable *KernelEnvGV =
4105 Changed = ChangeStatus::CHANGED;
4111 void insertInstructionGuardsHelper(Attributor &
A) {
4112 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
4114 auto CreateGuardedRegion = [&](
Instruction *RegionStartI,
4116 LoopInfo *LI =
nullptr;
4117 DominatorTree *DT =
nullptr;
4118 MemorySSAUpdater *MSU =
nullptr;
4147 DT, LI, MSU,
"region.guarded.end");
4150 MSU,
"region.barrier");
4153 DT, LI, MSU,
"region.exit");
4155 SplitBlock(ParentBB, RegionStartI, DT, LI, MSU,
"region.guarded");
4158 "Expected a different CFG");
4161 ParentBB, ParentBB->
getTerminator(), DT, LI, MSU,
"region.check.tid");
4164 A.registerManifestAddedBasicBlock(*RegionEndBB);
4165 A.registerManifestAddedBasicBlock(*RegionBarrierBB);
4166 A.registerManifestAddedBasicBlock(*RegionExitBB);
4167 A.registerManifestAddedBasicBlock(*RegionStartBB);
4168 A.registerManifestAddedBasicBlock(*RegionCheckTidBB);
4170 bool HasBroadcastValues =
false;
4173 for (Instruction &
I : *RegionStartBB) {
4175 for (Use &U :
I.uses()) {
4181 if (OutsideUses.
empty())
4184 HasBroadcastValues =
true;
4188 auto *SharedMem =
new GlobalVariable(
4189 M,
I.getType(),
false,
4191 sanitizeForGlobalName(
4192 (
I.getName() +
".guarded.output.alloc").str()),
4194 static_cast<unsigned>(AddressSpace::Shared));
4197 new StoreInst(&
I, SharedMem,
4200 LoadInst *LoadI =
new LoadInst(
4201 I.getType(), SharedMem,
I.getName() +
".guarded.output.load",
4205 for (Use *U : OutsideUses)
4206 A.changeUseAfterManifest(*U, *LoadI);
4209 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
4214 OpenMPIRBuilder::LocationDescription Loc(ParentBB->
end(),
DL);
4216 uint32_t SrcLocStrSize;
4225 OpenMPIRBuilder::LocationDescription LocRegionCheckTid(
4226 RegionCheckTidBB->
end(),
DL);
4228 FunctionCallee HardwareTidFn =
4230 M, OMPRTL___kmpc_get_hardware_thread_id_in_block);
4234 OMPInfoCache.setCallingConvention(HardwareTidFn, Tid);
4236 OMPInfoCache.OMPBuilder.
Builder
4237 .
CreateCondBr(TidCheck, RegionStartBB, RegionBarrierBB)
4242 FunctionCallee BarrierFn =
4244 M, OMPRTL___kmpc_barrier_simple_spmd);
4249 OMPInfoCache.setCallingConvention(BarrierFn, Barrier);
4252 if (HasBroadcastValues) {
4257 OMPInfoCache.setCallingConvention(BarrierFn, Barrier);
4261 auto &AllocSharedRFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
4262 SmallPtrSet<BasicBlock *, 8> Visited;
4263 for (Instruction *GuardedI : SPMDCompatibilityTracker) {
4265 if (!Visited.
insert(BB).second)
4271 while (++IP != IPEnd) {
4272 if (!IP->mayHaveSideEffects() && !IP->mayReadFromMemory())
4275 if (OpenMPOpt::getCallIfRegularCall(*
I, &AllocSharedRFI))
4277 if (!
I->user_empty() || !SPMDCompatibilityTracker.contains(
I)) {
4278 LastEffect =
nullptr;
4285 for (
auto &Reorder : Reorders)
4286 Reorder.first->moveBefore(Reorder.second->getIterator());
4291 for (Instruction *GuardedI : SPMDCompatibilityTracker) {
4293 auto *CalleeAA =
A.lookupAAFor<AAKernelInfo>(
4296 assert(CalleeAA !=
nullptr &&
"Expected Callee AAKernelInfo");
4299 if (CalleeAAFunction.getGuardedInstructions().contains(GuardedI))
4302 Instruction *GuardedRegionStart =
nullptr, *GuardedRegionEnd =
nullptr;
4303 for (Instruction &
I : *BB) {
4306 if (SPMDCompatibilityTracker.contains(&
I)) {
4307 CalleeAAFunction.getGuardedInstructions().insert(&
I);
4308 if (GuardedRegionStart)
4309 GuardedRegionEnd = &
I;
4311 GuardedRegionStart = GuardedRegionEnd = &
I;
4318 if (GuardedRegionStart) {
4320 std::make_pair(GuardedRegionStart, GuardedRegionEnd));
4321 GuardedRegionStart =
nullptr;
4322 GuardedRegionEnd =
nullptr;
4327 for (
auto &GR : GuardedRegions)
4328 CreateGuardedRegion(GR.first, GR.second);
4331 void forceSingleThreadPerWorkgroupHelper(Attributor &
A) {
4340 auto &Ctx = getAnchorValue().getContext();
4347 KernelInitCB->
getNextNode(),
"main.thread.user_code");
4352 A.registerManifestAddedBasicBlock(*InitBB);
4353 A.registerManifestAddedBasicBlock(*UserCodeBB);
4354 A.registerManifestAddedBasicBlock(*ReturnBB);
4363 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
4364 FunctionCallee ThreadIdInBlockFn =
4366 M, OMPRTL___kmpc_get_hardware_thread_id_in_block);
4369 CallInst *ThreadIdInBlock =
4371 OMPInfoCache.setCallingConvention(ThreadIdInBlockFn, ThreadIdInBlock);
4377 ConstantInt::get(ThreadIdInBlock->
getType(), 0),
4378 "thread.is_main", InitBB);
4384 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
4386 if (!SPMDCompatibilityTracker.isAssumed()) {
4387 for (Instruction *NonCompatibleI : SPMDCompatibilityTracker) {
4388 if (!NonCompatibleI)
4393 if (OMPInfoCache.RTLFunctions.contains(CB->getCalledFunction()))
4396 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
4397 ORA <<
"Value has potential side effects preventing SPMD-mode "
4400 ORA <<
". Add `[[omp::assume(\"ompx_spmd_amenable\")]]` to "
4401 "the called function to override";
4405 A.emitRemark<OptimizationRemarkAnalysis>(NonCompatibleI,
"OMP121",
4409 << *NonCompatibleI <<
"\n");
4421 Kernel = CB->getCaller();
4426 ConstantStruct *ExistingKernelEnvC =
4429 KernelInfo::getExecModeFromKernelEnvironment(ExistingKernelEnvC);
4435 Changed = ChangeStatus::CHANGED;
4439 if (mayContainParallelRegion())
4440 insertInstructionGuardsHelper(
A);
4442 forceSingleThreadPerWorkgroupHelper(
A);
4447 "Initially non-SPMD kernel has SPMD exec mode!");
4448 setExecModeOfKernelEnvironment(
4452 ++NumOpenMPTargetRegionKernelsSPMD;
4456 OMPInfoCache.SPMDizedKernels.insert(
Kernel);
4458 auto Remark = [&](OptimizationRemark
OR) {
4459 return OR <<
"Transformed generic-mode kernel to SPMD-mode.";
4461 A.emitRemark<OptimizationRemark>(KernelInitCB,
"OMP120",
Remark);
4471 if (!ReachedKnownParallelRegions.isValidState())
4474 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
4475 if (!OMPInfoCache.runtimeFnsAvailable({OMPRTL___kmpc_get_max_team_threads,
4476 OMPRTL___kmpc_barrier_simple_generic,
4477 OMPRTL___kmpc_kernel_parallel,
4478 OMPRTL___kmpc_kernel_end_parallel}))
4481 ConstantStruct *ExistingKernelEnvC =
4488 ConstantInt *UseStateMachineC =
4489 KernelInfo::getUseGenericStateMachineFromKernelEnvironment(
4490 ExistingKernelEnvC);
4491 ConstantInt *ModeC =
4492 KernelInfo::getExecModeFromKernelEnvironment(ExistingKernelEnvC);
4497 if (UseStateMachineC->
isZero() ||
4501 Changed = ChangeStatus::CHANGED;
4504 setUseGenericStateMachineOfKernelEnvironment(
4511 if (!mayContainParallelRegion()) {
4512 ++NumOpenMPTargetRegionKernelsWithoutStateMachine;
4514 auto Remark = [&](OptimizationRemark
OR) {
4515 return OR <<
"Removing unused state machine from generic-mode kernel.";
4517 A.emitRemark<OptimizationRemark>(KernelInitCB,
"OMP130",
Remark);
4523 if (ReachedUnknownParallelRegions.empty()) {
4524 ++NumOpenMPTargetRegionKernelsCustomStateMachineWithoutFallback;
4526 auto Remark = [&](OptimizationRemark
OR) {
4527 return OR <<
"Rewriting generic-mode kernel with a customized state "
4530 A.emitRemark<OptimizationRemark>(KernelInitCB,
"OMP131",
Remark);
4532 ++NumOpenMPTargetRegionKernelsCustomStateMachineWithFallback;
4534 auto Remark = [&](OptimizationRemarkAnalysis
OR) {
4535 return OR <<
"Generic-mode kernel is executed with a customized state "
4536 "machine that requires a fallback.";
4538 A.emitRemark<OptimizationRemarkAnalysis>(KernelInitCB,
"OMP132",
Remark);
4541 for (CallBase *UnknownParallelRegionCB : ReachedUnknownParallelRegions) {
4542 if (!UnknownParallelRegionCB)
4544 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
4545 return ORA <<
"Call may contain unknown parallel regions. Use "
4546 <<
"`[[omp::assume(\"omp_no_parallelism\")]]` to "
4549 A.emitRemark<OptimizationRemarkAnalysis>(UnknownParallelRegionCB,
4582 auto &Ctx = getAnchorValue().getContext();
4586 BasicBlock *InitBB = KernelInitCB->getParent();
4588 KernelInitCB->getNextNode(),
"thread.user_code.check");
4592 Ctx,
"worker_state_machine.begin",
Kernel, UserCodeEntryBB);
4594 Ctx,
"worker_state_machine.finished",
Kernel, UserCodeEntryBB);
4596 Ctx,
"worker_state_machine.is_active.check",
Kernel, UserCodeEntryBB);
4599 Kernel, UserCodeEntryBB);
4602 Kernel, UserCodeEntryBB);
4604 Ctx,
"worker_state_machine.done.barrier",
Kernel, UserCodeEntryBB);
4605 A.registerManifestAddedBasicBlock(*InitBB);
4606 A.registerManifestAddedBasicBlock(*UserCodeEntryBB);
4607 A.registerManifestAddedBasicBlock(*IsWorkerCheckBB);
4608 A.registerManifestAddedBasicBlock(*StateMachineBeginBB);
4609 A.registerManifestAddedBasicBlock(*StateMachineFinishedBB);
4610 A.registerManifestAddedBasicBlock(*StateMachineIsActiveCheckBB);
4611 A.registerManifestAddedBasicBlock(*StateMachineIfCascadeCurrentBB);
4612 A.registerManifestAddedBasicBlock(*StateMachineEndParallelBB);
4613 A.registerManifestAddedBasicBlock(*StateMachineDoneBarrierBB);
4615 const DebugLoc &DLoc = KernelInitCB->getDebugLoc();
4621 ConstantInt::getAllOnesValue(KernelInitCB->getType()),
4622 "thread.is_worker", InitBB);
4631 FunctionCallee MaxTeamThreadsFn =
4633 M, OMPRTL___kmpc_get_max_team_threads);
4634 Constant *IsSPMDArg = ConstantInt::get(OMPInfoCache.OMPBuilder.Int32, 0);
4636 MaxTeamThreadsFn, {IsSPMDArg},
"max_team_threads", IsWorkerCheckBB);
4637 OMPInfoCache.setCallingConvention(MaxTeamThreadsFn, MaxTeamThreads);
4641 "thread.is_main_or_worker", IsWorkerCheckBB);
4644 StateMachineFinishedBB, IsWorkerCheckBB);
4647 const DataLayout &
DL =
M.getDataLayout();
4648 Type *VoidPtrTy = PointerType::getUnqual(Ctx);
4650 new AllocaInst(VoidPtrTy,
DL.getAllocaAddrSpace(),
nullptr,
4655 OpenMPIRBuilder::LocationDescription(StateMachineBeginBB->
end(), DLoc));
4657 Value *Ident = KernelInfo::getIdentFromKernelEnvironment(KernelEnvC);
4658 Value *GTid = KernelInitCB;
4660 FunctionCallee BarrierFn =
4662 M, OMPRTL___kmpc_barrier_simple_generic);
4665 OMPInfoCache.setCallingConvention(BarrierFn, Barrier);
4669 (
unsigned int)AddressSpace::Generic) {
4670 WorkFnAI =
new AddrSpaceCastInst(
4671 WorkFnAI, PointerType::get(Ctx, (
unsigned int)AddressSpace::Generic),
4672 WorkFnAI->
getName() +
".generic", StateMachineBeginBB);
4676 FunctionCallee KernelParallelFn =
4678 M, OMPRTL___kmpc_kernel_parallel);
4680 KernelParallelFn, {WorkFnAI},
"worker.is_active", StateMachineBeginBB);
4681 OMPInfoCache.setCallingConvention(KernelParallelFn, IsActiveWorker);
4683 Instruction *WorkFn =
new LoadInst(VoidPtrTy, WorkFnAI,
"worker.work_fn",
4684 StateMachineBeginBB);
4687 FunctionType *ParallelRegionFnTy = FunctionType::get(
4688 Type::getVoidTy(Ctx), {Type::getInt16Ty(Ctx), Type::getInt32Ty(Ctx)},
4694 StateMachineBeginBB);
4695 IsDone->setDebugLoc(DLoc);
4697 StateMachineIsActiveCheckBB, StateMachineBeginBB)
4701 StateMachineDoneBarrierBB, StateMachineIsActiveCheckBB)
4707 const unsigned int WrapperFunctionArgNo = 6;
4712 for (
int I = 0,
E = ReachedKnownParallelRegions.size();
I <
E; ++
I) {
4713 auto *CB = ReachedKnownParallelRegions[
I];
4715 CB->getArgOperand(WrapperFunctionArgNo)->stripPointerCasts());
4717 Ctx,
"worker_state_machine.parallel_region.execute",
Kernel,
4718 StateMachineEndParallelBB);
4720 ->setDebugLoc(DLoc);
4726 Kernel, StateMachineEndParallelBB);
4727 A.registerManifestAddedBasicBlock(*PRExecuteBB);
4728 A.registerManifestAddedBasicBlock(*PRNextBB);
4733 if (
I + 1 <
E || !ReachedUnknownParallelRegions.empty()) {
4736 "worker.check_parallel_region", StateMachineIfCascadeCurrentBB);
4744 StateMachineIfCascadeCurrentBB)
4746 StateMachineIfCascadeCurrentBB = PRNextBB;
4752 if (!ReachedUnknownParallelRegions.empty()) {
4753 StateMachineIfCascadeCurrentBB->
setName(
4754 "worker_state_machine.parallel_region.fallback.execute");
4756 StateMachineIfCascadeCurrentBB)
4757 ->setDebugLoc(DLoc);
4760 StateMachineIfCascadeCurrentBB)
4763 FunctionCallee EndParallelFn =
4765 M, OMPRTL___kmpc_kernel_end_parallel);
4766 CallInst *EndParallel =
4768 OMPInfoCache.setCallingConvention(EndParallelFn, EndParallel);
4774 ->setDebugLoc(DLoc);
4784 KernelInfoState StateBefore = getState();
4790 struct UpdateKernelEnvCRAII {
4791 AAKernelInfoFunction &AA;
4793 UpdateKernelEnvCRAII(AAKernelInfoFunction &AA) : AA(AA) {}
4795 ~UpdateKernelEnvCRAII() {
4799 ConstantStruct *ExistingKernelEnvC =
4802 if (!AA.isValidState()) {
4803 AA.KernelEnvC = ExistingKernelEnvC;
4807 if (!AA.ReachedKnownParallelRegions.isValidState())
4808 AA.setUseGenericStateMachineOfKernelEnvironment(
4809 KernelInfo::getUseGenericStateMachineFromKernelEnvironment(
4810 ExistingKernelEnvC));
4812 if (!AA.SPMDCompatibilityTracker.isValidState())
4813 AA.setExecModeOfKernelEnvironment(
4814 KernelInfo::getExecModeFromKernelEnvironment(ExistingKernelEnvC));
4816 ConstantInt *MayUseNestedParallelismC =
4817 KernelInfo::getMayUseNestedParallelismFromKernelEnvironment(
4819 ConstantInt *NewMayUseNestedParallelismC = ConstantInt::get(
4820 MayUseNestedParallelismC->
getIntegerType(), AA.NestedParallelism);
4821 AA.setMayUseNestedParallelismOfKernelEnvironment(
4822 NewMayUseNestedParallelismC);
4832 if (!
I.mayWriteToMemory())
4835 const auto *UnderlyingObjsAA =
A.getAAFor<AAUnderlyingObjects>(
4837 DepClassTy::OPTIONAL);
4838 auto *
HS =
A.getAAFor<AAHeapToStack>(
4840 DepClassTy::OPTIONAL);
4841 if (UnderlyingObjsAA &&
4842 UnderlyingObjsAA->forallUnderlyingObjects([&](
Value &Obj) {
4843 if (AA::isAssumedThreadLocalObject(A, Obj, *this))
4847 auto *CB = dyn_cast<CallBase>(&Obj);
4848 return CB && HS && HS->isAssumedHeapToStack(*CB);
4854 SPMDCompatibilityTracker.insert(&
I);
4858 bool UsedAssumedInformationInCheckRWInst =
false;
4859 if (!SPMDCompatibilityTracker.isAtFixpoint())
4860 if (!
A.checkForAllReadWriteInstructions(
4861 CheckRWInst, *
this, UsedAssumedInformationInCheckRWInst))
4862 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
4864 bool UsedAssumedInformationFromReachingKernels =
false;
4865 if (!IsKernelEntry) {
4866 updateParallelLevels(
A);
4868 bool AllReachingKernelsKnown =
true;
4869 updateReachingKernelEntries(
A, AllReachingKernelsKnown);
4870 UsedAssumedInformationFromReachingKernels = !AllReachingKernelsKnown;
4872 if (!SPMDCompatibilityTracker.empty()) {
4873 if (!ParallelLevels.isValidState())
4874 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
4875 else if (!ReachingKernelEntries.isValidState())
4876 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
4882 for (
auto *
Kernel : ReachingKernelEntries) {
4883 auto *CBAA =
A.getAAFor<AAKernelInfo>(
4885 if (CBAA && CBAA->SPMDCompatibilityTracker.isValidState() &&
4886 CBAA->SPMDCompatibilityTracker.isAssumed())
4890 if (!CBAA || !CBAA->SPMDCompatibilityTracker.isAtFixpoint())
4891 UsedAssumedInformationFromReachingKernels =
true;
4893 if (SPMD != 0 &&
Generic != 0)
4894 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
4900 bool AllParallelRegionStatesWereFixed =
true;
4901 bool AllSPMDStatesWereFixed =
true;
4908 if (
Function *Callback = OMPInformationCache::getAnalyzableCallback(CB)) {
4910 <<
Callback->getName() <<
" of " << CB <<
"\n");
4911 if (
auto *CallbackAA =
A.getAAFor<AAKernelInfo>(
4913 getState() ^= CallbackAA->getState();
4914 AllSPMDStatesWereFixed &=
4915 CallbackAA->SPMDCompatibilityTracker.isAtFixpoint();
4916 AllParallelRegionStatesWereFixed &=
4917 CallbackAA->ReachedKnownParallelRegions.isAtFixpoint();
4918 AllParallelRegionStatesWereFixed &=
4919 CallbackAA->ReachedUnknownParallelRegions.isAtFixpoint();
4922 auto *CBAA =
A.getAAFor<AAKernelInfo>(
4926 getState() ^= CBAA->getState();
4927 AllSPMDStatesWereFixed &= CBAA->SPMDCompatibilityTracker.isAtFixpoint();
4928 AllParallelRegionStatesWereFixed &=
4929 CBAA->ReachedKnownParallelRegions.isAtFixpoint();
4930 AllParallelRegionStatesWereFixed &=
4931 CBAA->ReachedUnknownParallelRegions.isAtFixpoint();
4935 bool UsedAssumedInformationInCheckCallInst =
false;
4936 if (!
A.checkForAllCallLikeInstructions(
4937 CheckCallInst, *
this, UsedAssumedInformationInCheckCallInst)) {
4939 <<
"Failed to visit all call-like instructions!\n";);
4940 return indicatePessimisticFixpoint();
4945 if (!UsedAssumedInformationInCheckCallInst &&
4946 AllParallelRegionStatesWereFixed) {
4947 ReachedKnownParallelRegions.indicateOptimisticFixpoint();
4948 ReachedUnknownParallelRegions.indicateOptimisticFixpoint();
4953 if (!UsedAssumedInformationInCheckRWInst &&
4954 !UsedAssumedInformationInCheckCallInst &&
4955 !UsedAssumedInformationFromReachingKernels && AllSPMDStatesWereFixed)
4956 SPMDCompatibilityTracker.indicateOptimisticFixpoint();
4958 return StateBefore == getState() ? ChangeStatus::UNCHANGED
4959 : ChangeStatus::CHANGED;
4964 void updateReachingKernelEntries(Attributor &
A,
4965 bool &AllReachingKernelsKnown) {
4966 auto PredCallSite = [&](AbstractCallSite ACS) {
4969 assert(Caller &&
"Caller is nullptr");
4971 auto *CAA =
A.getOrCreateAAFor<AAKernelInfo>(
4973 if (CAA && CAA->ReachingKernelEntries.isValidState()) {
4974 ReachingKernelEntries ^= CAA->ReachingKernelEntries;
4980 ReachingKernelEntries.indicatePessimisticFixpoint();
4985 if (!
A.checkForAllCallSites(PredCallSite, *
this,
4987 AllReachingKernelsKnown))
4988 ReachingKernelEntries.indicatePessimisticFixpoint();
4992 void updateParallelLevels(Attributor &
A) {
4993 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
4994 OMPInformationCache::RuntimeFunctionInfo &Parallel60RFI =
4995 OMPInfoCache.RFIs[OMPRTL___kmpc_parallel_60];
4997 auto PredCallSite = [&](AbstractCallSite ACS) {
5000 assert(Caller &&
"Caller is nullptr");
5004 if (CAA && CAA->ParallelLevels.isValidState()) {
5010 if (Caller == Parallel60RFI.Declaration) {
5011 ParallelLevels.indicatePessimisticFixpoint();
5015 ParallelLevels ^= CAA->ParallelLevels;
5022 ParallelLevels.indicatePessimisticFixpoint();
5027 bool AllCallSitesKnown =
true;
5028 if (!
A.checkForAllCallSites(PredCallSite, *
this,
5031 ParallelLevels.indicatePessimisticFixpoint();
5038struct AAKernelInfoCallSite : AAKernelInfo {
5039 AAKernelInfoCallSite(
const IRPosition &IRP, Attributor &
A)
5040 : AAKernelInfo(IRP,
A) {}
5044 AAKernelInfo::initialize(
A);
5047 auto *AssumptionAA =
A.getAAFor<AAAssumptionInfo>(
5051 if (AssumptionAA && AssumptionAA->hasAssumption(
"ompx_spmd_amenable")) {
5052 indicateOptimisticFixpoint();
5060 indicateOptimisticFixpoint();
5069 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
5070 const auto &It = OMPInfoCache.RuntimeFunctionIDMap.find(Callee);
5071 if (It == OMPInfoCache.RuntimeFunctionIDMap.end()) {
5073 if (!Callee || !
A.isFunctionIPOAmendable(*Callee)) {
5077 if (!AssumptionAA ||
5078 !(AssumptionAA->hasAssumption(
"omp_no_openmp") ||
5079 AssumptionAA->hasAssumption(
"omp_no_parallelism")))
5080 ReachedUnknownParallelRegions.insert(&CB);
5084 if (!SPMDCompatibilityTracker.isAtFixpoint()) {
5085 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5086 SPMDCompatibilityTracker.insert(&CB);
5091 indicateOptimisticFixpoint();
5100 if (NumCallees > 1 && !
Callee->hasMetadata(LLVMContext::MD_callback)) {
5101 indicatePessimisticFixpoint();
5108 case OMPRTL___kmpc_is_spmd_exec_mode:
5109 case OMPRTL___kmpc_distribute_static_fini:
5110 case OMPRTL___kmpc_for_static_fini:
5111 case OMPRTL___kmpc_global_thread_num:
5112 case OMPRTL___kmpc_get_hardware_num_threads_in_block:
5113 case OMPRTL___kmpc_get_hardware_num_blocks:
5114 case OMPRTL___kmpc_single:
5115 case OMPRTL___kmpc_end_single:
5116 case OMPRTL___kmpc_master:
5117 case OMPRTL___kmpc_end_master:
5118 case OMPRTL___kmpc_barrier:
5119 case OMPRTL___kmpc_nvptx_parallel_reduce_nowait_v2:
5120 case OMPRTL___kmpc_gpu_xteam_reduce_nowait:
5121 case OMPRTL___kmpc_error:
5122 case OMPRTL___kmpc_flush:
5123 case OMPRTL___kmpc_get_hardware_thread_id_in_block:
5124 case OMPRTL___kmpc_get_warp_size:
5125 case OMPRTL_omp_get_thread_num:
5126 case OMPRTL_omp_get_num_threads:
5127 case OMPRTL_omp_get_max_threads:
5128 case OMPRTL_omp_in_parallel:
5129 case OMPRTL_omp_get_dynamic:
5130 case OMPRTL_omp_get_cancellation:
5131 case OMPRTL_omp_get_nested:
5132 case OMPRTL_omp_get_schedule:
5133 case OMPRTL_omp_get_thread_limit:
5134 case OMPRTL_omp_get_supported_active_levels:
5135 case OMPRTL_omp_get_max_active_levels:
5136 case OMPRTL_omp_get_level:
5137 case OMPRTL_omp_get_ancestor_thread_num:
5138 case OMPRTL_omp_get_team_size:
5139 case OMPRTL_omp_get_active_level:
5140 case OMPRTL_omp_in_final:
5141 case OMPRTL_omp_get_proc_bind:
5142 case OMPRTL_omp_get_num_places:
5143 case OMPRTL_omp_get_num_procs:
5144 case OMPRTL_omp_get_place_proc_ids:
5145 case OMPRTL_omp_get_place_num:
5146 case OMPRTL_omp_get_partition_num_places:
5147 case OMPRTL_omp_get_partition_place_nums:
5148 case OMPRTL_omp_get_wtime:
5150 case OMPRTL___kmpc_distribute_static_init_4:
5151 case OMPRTL___kmpc_distribute_static_init_4u:
5152 case OMPRTL___kmpc_distribute_static_init_8:
5153 case OMPRTL___kmpc_distribute_static_init_8u:
5154 case OMPRTL___kmpc_for_static_init_4:
5155 case OMPRTL___kmpc_for_static_init_4u:
5156 case OMPRTL___kmpc_for_static_init_8:
5157 case OMPRTL___kmpc_for_static_init_8u: {
5159 unsigned ScheduleArgOpNo = 2;
5160 auto *ScheduleTypeCI =
5162 unsigned ScheduleTypeVal =
5163 ScheduleTypeCI ? ScheduleTypeCI->getZExtValue() : 0;
5165 case OMPScheduleType::UnorderedStatic:
5166 case OMPScheduleType::UnorderedStaticChunked:
5167 case OMPScheduleType::OrderedDistribute:
5168 case OMPScheduleType::OrderedDistributeChunked:
5171 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5172 SPMDCompatibilityTracker.insert(&CB);
5176 case OMPRTL___kmpc_target_init:
5179 case OMPRTL___kmpc_target_deinit:
5180 KernelDeinitCB = &CB;
5182 case OMPRTL___kmpc_parallel_60:
5183 if (!handleParallel60(
A, CB))
5184 indicatePessimisticFixpoint();
5186 case OMPRTL___kmpc_omp_task:
5188 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5189 SPMDCompatibilityTracker.insert(&CB);
5190 ReachedUnknownParallelRegions.insert(&CB);
5192 case OMPRTL___kmpc_alloc_shared:
5193 case OMPRTL___kmpc_free_shared:
5201 case OMPRTL___kmpc_distribute_static_loop_4:
5202 case OMPRTL___kmpc_distribute_static_loop_4u:
5203 case OMPRTL___kmpc_distribute_static_loop_8:
5204 case OMPRTL___kmpc_distribute_static_loop_8u:
5212 if (!OMPInformationCache::getAnalyzableCallback(CB))
5213 ReachedUnknownParallelRegions.insert(&CB);
5214 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5215 SPMDCompatibilityTracker.insert(&CB);
5217 case OMPRTL___kmpc_distribute_for_static_loop_4:
5218 case OMPRTL___kmpc_distribute_for_static_loop_4u:
5219 case OMPRTL___kmpc_distribute_for_static_loop_8:
5220 case OMPRTL___kmpc_distribute_for_static_loop_8u:
5221 case OMPRTL___kmpc_for_static_loop_4:
5222 case OMPRTL___kmpc_for_static_loop_4u:
5223 case OMPRTL___kmpc_for_static_loop_8:
5224 case OMPRTL___kmpc_for_static_loop_8u:
5233 if (!OMPInformationCache::getAnalyzableCallback(CB))
5234 ReachedUnknownParallelRegions.insert(&CB);
5235 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5236 SPMDCompatibilityTracker.insert(&CB);
5241 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5242 SPMDCompatibilityTracker.insert(&CB);
5248 indicateOptimisticFixpoint();
5252 A.getAAFor<AACallEdges>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
5253 if (!AACE || !AACE->getState().isValidState() || AACE->hasUnknownCallee()) {
5254 CheckCallee(getAssociatedFunction(), 1);
5257 const auto &OptimisticEdges = AACE->getOptimisticEdges();
5258 for (
auto *Callee : OptimisticEdges) {
5259 CheckCallee(Callee, OptimisticEdges.size());
5270 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
5271 KernelInfoState StateBefore = getState();
5273 auto CheckCallee = [&](
Function *
F,
int NumCallees) {
5274 const auto &It = OMPInfoCache.RuntimeFunctionIDMap.find(
F);
5278 if (It == OMPInfoCache.RuntimeFunctionIDMap.end()) {
5281 A.getAAFor<AAKernelInfo>(*
this, FnPos, DepClassTy::REQUIRED);
5283 return indicatePessimisticFixpoint();
5284 if (getState() == FnAA->getState())
5285 return ChangeStatus::UNCHANGED;
5286 getState() = FnAA->getState();
5287 return ChangeStatus::CHANGED;
5291 if (NumCallees > 1 && !
F->hasMetadata(LLVMContext::MD_callback))
5292 return indicatePessimisticFixpoint();
5295 if (It->getSecond() == OMPRTL___kmpc_parallel_60) {
5296 if (!handleParallel60(
A, CB))
5297 return indicatePessimisticFixpoint();
5298 return StateBefore == getState() ? ChangeStatus::UNCHANGED
5299 : ChangeStatus::CHANGED;
5305 (It->getSecond() == OMPRTL___kmpc_alloc_shared ||
5306 It->getSecond() == OMPRTL___kmpc_free_shared) &&
5307 "Expected a __kmpc_alloc_shared or __kmpc_free_shared runtime call");
5309 auto *HeapToStackAA =
A.getAAFor<AAHeapToStack>(
5311 auto *HeapToSharedAA =
A.getAAFor<AAHeapToShared>(
5319 case OMPRTL___kmpc_alloc_shared:
5320 if ((!HeapToStackAA || !HeapToStackAA->isAssumedHeapToStack(CB)) &&
5321 (!HeapToSharedAA || !HeapToSharedAA->isAssumedHeapToShared(CB)))
5322 SPMDCompatibilityTracker.insert(&CB);
5324 case OMPRTL___kmpc_free_shared:
5325 if ((!HeapToStackAA ||
5326 !HeapToStackAA->isAssumedHeapToStackRemovedFree(CB)) &&
5328 !HeapToSharedAA->isAssumedHeapToSharedRemovedFree(CB)))
5329 SPMDCompatibilityTracker.insert(&CB);
5332 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5333 SPMDCompatibilityTracker.insert(&CB);
5335 return ChangeStatus::CHANGED;
5339 A.getAAFor<AACallEdges>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
5340 if (!AACE || !AACE->getState().isValidState() || AACE->hasUnknownCallee()) {
5341 if (
Function *
F = getAssociatedFunction())
5344 const auto &OptimisticEdges = AACE->getOptimisticEdges();
5345 for (
auto *Callee : OptimisticEdges) {
5346 CheckCallee(Callee, OptimisticEdges.size());
5352 return StateBefore == getState() ? ChangeStatus::UNCHANGED
5353 : ChangeStatus::CHANGED;
5358 bool handleParallel60(Attributor &
A, CallBase &CB) {
5359 const unsigned int NonWrapperFunctionArgNo = 5;
5360 const unsigned int WrapperFunctionArgNo = 6;
5361 auto ParallelRegionOpArgNo = SPMDCompatibilityTracker.isAssumed()
5362 ? NonWrapperFunctionArgNo
5363 : WrapperFunctionArgNo;
5367 if (!ParallelRegion)
5370 ReachedKnownParallelRegions.insert(&CB);
5372 auto *FnAA =
A.getAAFor<AAKernelInfo>(
5374 NestedParallelism |= !FnAA || !FnAA->getState().isValidState() ||
5375 !FnAA->ReachedKnownParallelRegions.empty() ||
5376 !FnAA->ReachedKnownParallelRegions.isValidState() ||
5377 !FnAA->ReachedUnknownParallelRegions.isValidState() ||
5378 !FnAA->ReachedUnknownParallelRegions.empty();
5383struct AAFoldRuntimeCall
5384 :
public StateWrapper<BooleanState, AbstractAttribute> {
5385 using Base = StateWrapper<BooleanState, AbstractAttribute>;
5387 AAFoldRuntimeCall(
const IRPosition &IRP, Attributor &
A) :
Base(IRP) {}
5390 void trackStatistics()
const override {}
5393 static AAFoldRuntimeCall &createForPosition(
const IRPosition &IRP,
5397 StringRef
getName()
const override {
return "AAFoldRuntimeCall"; }
5400 const char *getIdAddr()
const override {
return &ID; }
5404 static bool classof(
const AbstractAttribute *AA) {
5408 static const char ID;
5411struct AAFoldRuntimeCallCallSiteReturned : AAFoldRuntimeCall {
5412 AAFoldRuntimeCallCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5413 : AAFoldRuntimeCall(IRP,
A) {}
5416 const std::string getAsStr(Attributor *)
const override {
5417 if (!isValidState())
5420 std::string Str(
"simplified value: ");
5422 if (!SimplifiedValue)
5423 return Str + std::string(
"none");
5425 if (!*SimplifiedValue)
5426 return Str + std::string(
"nullptr");
5429 return Str + std::to_string(CI->getSExtValue());
5431 return Str + std::string(
"unknown");
5436 indicatePessimisticFixpoint();
5440 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
5441 const auto &It = OMPInfoCache.RuntimeFunctionIDMap.find(Callee);
5442 assert(It != OMPInfoCache.RuntimeFunctionIDMap.end() &&
5443 "Expected a known OpenMP runtime function");
5445 RFKind = It->getSecond();
5448 A.registerSimplificationCallback(
5450 [&](
const IRPosition &IRP,
const AbstractAttribute *AA,
5451 bool &UsedAssumedInformation) -> std::optional<Value *> {
5452 assert((isValidState() || SimplifiedValue ==
nullptr) &&
5453 "Unexpected invalid state!");
5455 if (!isAtFixpoint()) {
5456 UsedAssumedInformation =
true;
5458 A.recordDependence(*
this, *AA, DepClassTy::OPTIONAL);
5460 return SimplifiedValue;
5467 case OMPRTL___kmpc_is_spmd_exec_mode:
5470 case OMPRTL___kmpc_parallel_level:
5473 case OMPRTL___kmpc_get_hardware_num_threads_in_block:
5474 Changed =
Changed | foldKernelFnAttribute(
A,
"omp_target_thread_limit");
5476 case OMPRTL___kmpc_get_hardware_num_blocks:
5489 if (SimplifiedValue && *SimplifiedValue) {
5492 A.deleteAfterManifest(
I);
5495 auto Remark = [&](OptimizationRemark
OR) {
5497 return OR <<
"Replacing OpenMP runtime call "
5499 <<
ore::NV(
"FoldedValue",
C->getZExtValue()) <<
".";
5500 return OR <<
"Replacing OpenMP runtime call "
5505 A.emitRemark<OptimizationRemark>(CB,
"OMP180",
Remark);
5508 << **SimplifiedValue <<
"\n");
5510 Changed = ChangeStatus::CHANGED;
5517 SimplifiedValue =
nullptr;
5518 return AAFoldRuntimeCall::indicatePessimisticFixpoint();
5524 std::optional<Value *> SimplifiedValueBefore = SimplifiedValue;
5526 unsigned AssumedSPMDCount = 0, KnownSPMDCount = 0;
5527 unsigned AssumedNonSPMDCount = 0, KnownNonSPMDCount = 0;
5528 auto *CallerKernelInfoAA =
A.getAAFor<AAKernelInfo>(
5531 if (!CallerKernelInfoAA ||
5532 !CallerKernelInfoAA->ReachingKernelEntries.isValidState())
5533 return indicatePessimisticFixpoint();
5535 for (
Kernel K : CallerKernelInfoAA->ReachingKernelEntries) {
5537 DepClassTy::REQUIRED);
5539 if (!AA || !AA->isValidState()) {
5540 SimplifiedValue =
nullptr;
5541 return indicatePessimisticFixpoint();
5544 if (AA->SPMDCompatibilityTracker.isAssumed()) {
5545 if (AA->SPMDCompatibilityTracker.isAtFixpoint())
5550 if (AA->SPMDCompatibilityTracker.isAtFixpoint())
5551 ++KnownNonSPMDCount;
5553 ++AssumedNonSPMDCount;
5557 if ((AssumedSPMDCount + KnownSPMDCount) &&
5558 (AssumedNonSPMDCount + KnownNonSPMDCount))
5559 return indicatePessimisticFixpoint();
5561 auto &Ctx = getAnchorValue().getContext();
5562 if (KnownSPMDCount || AssumedSPMDCount) {
5563 assert(KnownNonSPMDCount == 0 && AssumedNonSPMDCount == 0 &&
5564 "Expected only SPMD kernels!");
5567 SimplifiedValue = ConstantInt::get(Type::getInt8Ty(Ctx),
true);
5568 }
else if (KnownNonSPMDCount || AssumedNonSPMDCount) {
5569 assert(KnownSPMDCount == 0 && AssumedSPMDCount == 0 &&
5570 "Expected only non-SPMD kernels!");
5573 SimplifiedValue = ConstantInt::get(Type::getInt8Ty(Ctx),
false);
5578 assert(!SimplifiedValue &&
"SimplifiedValue should be none");
5581 return SimplifiedValue == SimplifiedValueBefore ? ChangeStatus::UNCHANGED
5582 : ChangeStatus::CHANGED;
5587 std::optional<Value *> SimplifiedValueBefore = SimplifiedValue;
5589 auto *CallerKernelInfoAA =
A.getAAFor<AAKernelInfo>(
5592 if (!CallerKernelInfoAA ||
5593 !CallerKernelInfoAA->ParallelLevels.isValidState())
5594 return indicatePessimisticFixpoint();
5596 if (!CallerKernelInfoAA->ReachingKernelEntries.isValidState())
5597 return indicatePessimisticFixpoint();
5599 if (CallerKernelInfoAA->ReachingKernelEntries.empty()) {
5600 assert(!SimplifiedValue &&
5601 "SimplifiedValue should keep none at this point");
5602 return ChangeStatus::UNCHANGED;
5605 unsigned AssumedSPMDCount = 0, KnownSPMDCount = 0;
5606 unsigned AssumedNonSPMDCount = 0, KnownNonSPMDCount = 0;
5607 for (
Kernel K : CallerKernelInfoAA->ReachingKernelEntries) {
5609 DepClassTy::REQUIRED);
5610 if (!AA || !AA->SPMDCompatibilityTracker.isValidState())
5611 return indicatePessimisticFixpoint();
5613 if (AA->SPMDCompatibilityTracker.isAssumed()) {
5614 if (AA->SPMDCompatibilityTracker.isAtFixpoint())
5619 if (AA->SPMDCompatibilityTracker.isAtFixpoint())
5620 ++KnownNonSPMDCount;
5622 ++AssumedNonSPMDCount;
5626 if ((AssumedSPMDCount + KnownSPMDCount) &&
5627 (AssumedNonSPMDCount + KnownNonSPMDCount))
5628 return indicatePessimisticFixpoint();
5630 auto &Ctx = getAnchorValue().getContext();
5634 if (AssumedSPMDCount || KnownSPMDCount) {
5635 assert(KnownNonSPMDCount == 0 && AssumedNonSPMDCount == 0 &&
5636 "Expected only SPMD kernels!");
5637 SimplifiedValue = ConstantInt::get(Type::getInt8Ty(Ctx), 1);
5639 assert(KnownSPMDCount == 0 && AssumedSPMDCount == 0 &&
5640 "Expected only non-SPMD kernels!");
5641 SimplifiedValue = ConstantInt::get(Type::getInt8Ty(Ctx), 0);
5643 return SimplifiedValue == SimplifiedValueBefore ? ChangeStatus::UNCHANGED
5644 : ChangeStatus::CHANGED;
5647 ChangeStatus foldKernelFnAttribute(Attributor &
A, llvm::StringRef Attr) {
5649 int32_t CurrentAttrValue = -1;
5650 std::optional<Value *> SimplifiedValueBefore = SimplifiedValue;
5652 auto *CallerKernelInfoAA =
A.getAAFor<AAKernelInfo>(
5655 if (!CallerKernelInfoAA ||
5656 !CallerKernelInfoAA->ReachingKernelEntries.isValidState())
5657 return indicatePessimisticFixpoint();
5660 for (
Kernel K : CallerKernelInfoAA->ReachingKernelEntries) {
5661 int32_t NextAttrVal =
K->getFnAttributeAsParsedInteger(Attr, -1);
5663 if (NextAttrVal == -1 ||
5664 (CurrentAttrValue != -1 && CurrentAttrValue != NextAttrVal))
5665 return indicatePessimisticFixpoint();
5666 CurrentAttrValue = NextAttrVal;
5669 if (CurrentAttrValue != -1) {
5670 auto &Ctx = getAnchorValue().getContext();
5672 ConstantInt::get(Type::getInt32Ty(Ctx), CurrentAttrValue);
5674 return SimplifiedValue == SimplifiedValueBefore ? ChangeStatus::UNCHANGED
5675 : ChangeStatus::CHANGED;
5681 std::optional<Value *> SimplifiedValue;
5691 auto &RFI = OMPInfoCache.RFIs[RF];
5692 RFI.foreachUse(SCC, [&](Use &U,
Function &
F) {
5693 CallInst *CI = OpenMPOpt::getCallIfRegularCall(U, &RFI);
5696 A.getOrCreateAAFor<AAFoldRuntimeCall>(
5698 DepClassTy::NONE,
false,
5704void OpenMPOpt::registerAAs(
bool IsModulePass) {
5714 A.getOrCreateAAFor<AAKernelInfo>(
5716 DepClassTy::NONE,
false,
5720 OMPInformationCache::RuntimeFunctionInfo &InitRFI =
5721 OMPInfoCache.RFIs[OMPRTL___kmpc_target_init];
5722 InitRFI.foreachUse(SCC, CreateKernelInfoCB);
5724 registerFoldRuntimeCall(OMPRTL___kmpc_is_spmd_exec_mode);
5725 registerFoldRuntimeCall(OMPRTL___kmpc_parallel_level);
5726 registerFoldRuntimeCall(OMPRTL___kmpc_get_hardware_num_threads_in_block);
5727 registerFoldRuntimeCall(OMPRTL___kmpc_get_hardware_num_blocks);
5732 for (
int Idx = 0; Idx < OMPInfoCache.ICVs.size() - 1; ++Idx) {
5735 auto &GetterRFI = OMPInfoCache.RFIs[ICVInfo.Getter];
5738 CallInst *CI = OpenMPOpt::getCallIfRegularCall(U, &GetterRFI);
5745 A.getOrCreateAAFor<AAICVTracker>(CBPos);
5749 GetterRFI.foreachUse(SCC, CreateAA);
5758 for (
auto *
F : SCC) {
5759 if (
F->isDeclaration())
5765 if (
F->hasLocalLinkage()) {
5767 const auto *CB = dyn_cast<CallBase>(U.getUser());
5768 return CB && CB->isCallee(&U) &&
5769 A.isRunOn(const_cast<Function *>(CB->getCaller()));
5773 registerAAsForFunction(
A, *
F);
5777void OpenMPOpt::registerAAsForFunction(Attributor &
A,
const Function &
F) {
5778 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
5781 A.getOrCreateAAFor<AAExecutionDomain>(FPos);
5782 if (
F.hasFnAttribute(Attribute::Convergent))
5783 A.getOrCreateAAFor<AANonConvergent>(FPos);
5785 bool FunctionUsesSharedAlloc =
false;
5787 const OMPInformationCache::RuntimeFunctionInfo::UseVector *SharedAllocUses =
5788 OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared].getUseVector(
5790 FunctionUsesSharedAlloc = SharedAllocUses && !SharedAllocUses->
empty();
5792 bool HasHeapToStackCandidate =
false;
5793 const TargetLibraryInfo *TLI =
nullptr;
5797 bool UsedAssumedInformation =
false;
5800 A.getOrCreateAAFor<AAAddressSpace>(
5807 TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(
F);
5808 HasHeapToStackCandidate =
5812 A.getOrCreateAAFor<AAIndirectCallInfo>(
5817 A.getOrCreateAAFor<AAAddressSpace>(
5826 if (
II->getIntrinsicID() == Intrinsic::assume) {
5827 A.getOrCreateAAFor<AAPotentialValues>(
5834 if (FunctionUsesSharedAlloc)
5835 A.getOrCreateAAFor<AAHeapToShared>(FPos);
5836 if (HasHeapToStackCandidate)
5837 A.getOrCreateAAFor<AAHeapToStack>(FPos);
5840const char AAICVTracker::ID = 0;
5841const char AAKernelInfo::ID = 0;
5843const char AAHeapToShared::ID = 0;
5844const char AAFoldRuntimeCall::ID = 0;
5846AAICVTracker &AAICVTracker::createForPosition(
const IRPosition &IRP,
5848 AAICVTracker *AA =
nullptr;
5856 AA =
new (
A.Allocator) AAICVTrackerFunctionReturned(IRP,
A);
5859 AA =
new (
A.Allocator) AAICVTrackerCallSiteReturned(IRP,
A);
5862 AA =
new (
A.Allocator) AAICVTrackerCallSite(IRP,
A);
5865 AA =
new (
A.Allocator) AAICVTrackerFunction(IRP,
A);
5874 AAExecutionDomainFunction *
AA =
nullptr;
5884 "AAExecutionDomain can only be created for function position!");
5886 AA =
new (
A.Allocator) AAExecutionDomainFunction(IRP,
A);
5893AAHeapToShared &AAHeapToShared::createForPosition(
const IRPosition &IRP,
5895 AAHeapToSharedFunction *
AA =
nullptr;
5905 "AAHeapToShared can only be created for function position!");
5907 AA =
new (
A.Allocator) AAHeapToSharedFunction(IRP,
A);
5914AAKernelInfo &AAKernelInfo::createForPosition(
const IRPosition &IRP,
5916 AAKernelInfo *AA =
nullptr;
5926 AA =
new (
A.Allocator) AAKernelInfoCallSite(IRP,
A);
5929 AA =
new (
A.Allocator) AAKernelInfoFunction(IRP,
A);
5936AAFoldRuntimeCall &AAFoldRuntimeCall::createForPosition(
const IRPosition &IRP,
5938 AAFoldRuntimeCall *AA =
nullptr;
5947 llvm_unreachable(
"KernelInfo can only be created for call site position!");
5949 AA =
new (
A.Allocator) AAFoldRuntimeCallCallSiteReturned(IRP,
A);
5969 unsigned NumAssumedCallees) {
5987 if (Kernels.contains(&
F))
5989 return !
F.use_empty();
5996 return ORA <<
"Could not internalize function. "
5997 <<
"Some optimizations may not be possible. [OMP140]";
6009 if (!
F.isDeclaration() && !Kernels.contains(&
F) && IsCalled(
F) &&
6013 }
else if (!
F.hasLocalLinkage() && !
F.hasFnAttribute(Attribute::Cold)) {
6026 if (!
F.isDeclaration() && !InternalizedMap.
lookup(&
F)) {
6028 Functions.insert(&
F);
6046 OMPInformationCache InfoCache(M, AG, Allocator,
nullptr, PostLink);
6048 unsigned MaxFixpointIterations =
6061 return F.hasFnAttribute(
"kernel");
6066 OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache,
A);
6072 if (!
F.isDeclaration() && !Kernels.contains(&
F) &&
6073 !
F.hasFnAttribute(Attribute::NoInline))
6074 F.addFnAttr(Attribute::AlwaysInline);
6104 Module &M = *
C.begin()->getFunction().getParent();
6126 OMPInformationCache InfoCache(*(Functions.back()->getParent()), AG, Allocator,
6127 &Functions, PostLink);
6129 unsigned MaxFixpointIterations =
6144 OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache,
A);
6145 bool Changed = OMPOpt.run(
false);
6164 if (
F.hasKernelCallingConv()) {
6169 ++NumOpenMPTargetRegionKernels;
6172 ++NumNonOpenMPTargetRegionKernels;
6179 Metadata *MD = M.getModuleFlag(
"openmp");
6187 Metadata *MD = M.getModuleFlag(
"openmp-device");
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
amdgpu aa AMDGPU Address space based Alias Analysis Wrapper
amdgpu next use AMDGPU Next Use Analysis Printer
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
static cl::opt< unsigned > SetFixpointIterations("attributor-max-iterations", cl::Hidden, cl::desc("Maximal number of fixpoint iterations."), cl::init(32))
static const Function * getParent(const Value *V)
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file provides interfaces used to manipulate a call graph, regardless if it is a "old style" Call...
This file provides interfaces used to build and manipulate a call graph, which is a very useful tool ...
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file defines the DenseSet and SmallDenseSet classes.
This file defines an array type that can be indexed using scoped enum values.
static void emitRemark(const Function &F, OptimizationRemarkEmitter &ORE, bool Skip)
Loop::LoopBounds::Direction Direction
Machine Check Debug Module
This file provides utility analysis objects describing memory locations.
uint64_t IntrinsicInst * II
This file defines constans and helpers used when dealing with OpenMP.
This file defines constans that will be used by both host and device compilation.
static constexpr auto TAG
static cl::opt< bool > HideMemoryTransferLatency("openmp-hide-memory-transfer-latency", cl::desc("[WIP] Tries to hide the latency of host to device memory" " transfers"), cl::Hidden, cl::init(false))
static cl::opt< bool > DisableOpenMPOptStateMachineRewrite("openmp-opt-disable-state-machine-rewrite", cl::desc("Disable OpenMP optimizations that replace the state machine."), cl::Hidden, cl::init(false))
static cl::opt< bool > EnableParallelRegionMerging("openmp-opt-enable-merging", cl::desc("Enable the OpenMP region merging optimization."), cl::Hidden, cl::init(false))
static cl::opt< bool > PrintModuleAfterOptimizations("openmp-opt-print-module-after", cl::desc("Print the current module after OpenMP optimizations."), cl::Hidden, cl::init(false))
#define KERNEL_ENVIRONMENT_CONFIGURATION_GETTER(MEMBER)
#define KERNEL_ENVIRONMENT_CONFIGURATION_IDX(MEMBER, IDX)
#define KERNEL_ENVIRONMENT_CONFIGURATION_SETTER(MEMBER)
static cl::opt< bool > PrintOpenMPKernels("openmp-print-gpu-kernels", cl::init(false), cl::Hidden)
static cl::opt< bool > DisableOpenMPOptFolding("openmp-opt-disable-folding", cl::desc("Disable OpenMP optimizations involving folding."), cl::Hidden, cl::init(false))
static bool shouldSpecializeIndirectCallee(Attributor &, const AbstractAttribute &, CallBase &, Function &, unsigned NumAssumedCallees)
Bound the if-cascade AAIndirectCallInfo builds for an indirect call.
static cl::opt< bool > PrintModuleBeforeOptimizations("openmp-opt-print-module-before", cl::desc("Print the current module before OpenMP optimizations."), cl::Hidden, cl::init(false))
static cl::opt< unsigned > SetFixpointIterations("openmp-opt-max-iterations", cl::Hidden, cl::desc("Maximal number of attributor iterations."), cl::init(256))
static cl::opt< bool > DisableInternalization("openmp-opt-disable-internalization", cl::desc("Disable function internalization."), cl::Hidden, cl::init(false))
static cl::opt< bool > PrintICVValues("openmp-print-icv-values", cl::init(false), cl::Hidden)
static cl::opt< bool > DisableOpenMPOptimizations("openmp-opt-disable", cl::desc("Disable OpenMP specific optimizations."), cl::Hidden, cl::init(false))
static cl::opt< unsigned > SharedMemoryLimit("openmp-opt-shared-limit", cl::Hidden, cl::desc("Maximum amount of shared memory to use."), cl::init(std::numeric_limits< unsigned >::max()))
static cl::opt< bool > EnableVerboseRemarks("openmp-opt-verbose-remarks", cl::desc("Enables more verbose remarks."), cl::Hidden, cl::init(false))
static cl::opt< unsigned > MaxCalleesForSpecialization("openmp-opt-max-callees-for-specialization", cl::Hidden, cl::desc("Number of possible callees above which an indirect call site is " "left alone rather than specialized into an if-cascade."), cl::init(3))
static cl::opt< bool > DisableOpenMPOptDeglobalization("openmp-opt-disable-deglobalization", cl::desc("Disable OpenMP optimizations involving deglobalization."), cl::Hidden, cl::init(false))
static cl::opt< bool > DisableOpenMPOptBarrierElimination("openmp-opt-disable-barrier-elimination", cl::desc("Disable OpenMP optimizations that eliminate barriers."), cl::Hidden, cl::init(false))
static cl::opt< bool > DeduceICVValues("openmp-deduce-icv-values", cl::init(false), cl::Hidden)
#define KERNEL_ENVIRONMENT_IDX(MEMBER, IDX)
#define KERNEL_ENVIRONMENT_GETTER(MEMBER, RETURNTYPE)
static cl::opt< bool > DisableOpenMPOptSPMDization("openmp-opt-disable-spmdization", cl::desc("Disable OpenMP optimizations involving SPMD-ization."), cl::Hidden, cl::init(false))
static cl::opt< bool > AlwaysInlineDeviceFunctions("openmp-opt-inline-device", cl::desc("Inline all applicable functions on the device."), cl::Hidden, cl::init(false))
FunctionAnalysisManager FAM
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
This file contains the declarations for profiling metadata utility functions.
static StringRef getName(Value *V)
Remove Loads Into Fake Uses
std::pair< BasicBlock *, BasicBlock * > Edge
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T, const llvm::StringTable &StandardNames, VectorLibrary VecLib)
Initialize the set of available library functions based on the specified target triple.
static cl::opt< unsigned > MaxThreads("xcore-max-threads", 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.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
iterator begin()
Instruction iterator methods.
LLVM_ABI const_iterator getFirstInsertionPt() const
Returns an iterator to the first instruction in this block that is suitable for inserting a non-PHI i...
LLVM_ABI BasicBlock * splitBasicBlock(iterator I, const Twine &BBName="")
Split the basic block into two basic blocks at the specified instruction.
const Function * getParent() const
Return the enclosing method, or null if none.
reverse_iterator rbegin()
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
LLVM_ABI const BasicBlock * getUniqueSuccessor() const
Return the successor of this block if it has a unique successor.
InstListType::reverse_iterator reverse_iterator
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
void setCallingConv(CallingConv::ID CC)
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
bool doesNotAccessMemory(unsigned OpNo) const
bool hasFnAttr(Attribute::AttrKind Kind) const
Determine whether this call has the given attribute.
LLVM_ABI bool isIndirectCall() const
Return true if the callsite is an indirect call.
bool isCallee(Value::const_user_iterator UI) const
Determine whether the passed iterator points to the callee operand's Use.
Value * getCalledOperand() const
Value * getArgOperand(unsigned i) const
void setArgOperand(unsigned i, Value *v)
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
unsigned getArgOperandNo(const Use *U) const
Given a use for a arg operand, get the arg operand number that corresponds to it.
unsigned arg_size() const
AttributeList getAttributes() const
Return the attributes for this call.
void addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind)
Adds the attribute to the indicated argument.
bool isArgOperand(const Use *U) const
bool hasOperandBundles() const
Return true if this User has any operand bundles.
LLVM_ABI Function * getCaller()
Helper to get the caller (the parent function).
Wrapper to unify "old style" CallGraph and "new style" LazyCallGraph.
void initialize(LazyCallGraph &LCG, LazyCallGraph::SCC &SCC, CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR)
Initializers for usage outside of a CGSCC pass, inside a CGSCC pass in the old and new pass manager (...
This class represents a function call, abstracting a target machine's calling convention.
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
@ ICMP_SLT
signed less than
static CondBrInst * Create(Value *Cond, BasicBlock *IfTrue, BasicBlock *IfFalse, InsertPosition InsertBefore=nullptr)
static LLVM_ABI Constant * getPointerCast(Constant *C, Type *Ty)
Create a BitCast, AddrSpaceCast, or a PtrToInt cast constant expression.
static LLVM_ABI Constant * getPointerBitCastOrAddrSpaceCast(Constant *C, Type *Ty)
Create a BitCast or AddrSpaceCast for a pointer type depending on the address space.
This is the shared class of boolean and integer constants.
IntegerType * getIntegerType() const
Variant of the getType() method to always return an IntegerType, which reduces the amount of casting ...
static LLVM_ABI ConstantInt * getTrue(LLVMContext &Context)
bool isZero() const
This is just a convenience method to make client code smaller for a common code.
int64_t getSExtValue() const
Return the constant as a 64-bit integer value after it has been sign extended as appropriate for the ...
static LLVM_ABI ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
This is an important base class in LLVM.
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
ValueT lookup(const_arg_type_t< KeyT > Val) const
Return the entry for the specified key, or a default constructed value if no such entry exists.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
LLVM_ABI Instruction * findNearestCommonDominator(Instruction *I1, Instruction *I2) const
Find the nearest instruction I that dominates both I1 and I2, in the sense that a result produced bef...
static ErrorSuccess success()
Create a success value.
AtomicOrdering getOrdering() const
Returns the ordering constraint of this fence instruction.
A proxy from a FunctionAnalysisManager to an SCC.
const BasicBlock & getEntryBlock() const
const BasicBlock & front() const
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
void setEntryCount(uint64_t Count, const DenseSet< GlobalValue::GUID > *Imports=nullptr)
Set the entry count for this function.
Argument * getArg(unsigned i) const
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
LLVM_ABI bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
bool hasLocalLinkage() const
Module * getParent()
Get the module that this global value is contained inside of...
@ PrivateLinkage
Like Internal, but omit from symbol table.
@ InternalLinkage
Rename collisions when linking (static functions).
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
LLVM_ABI void setInitializer(Constant *InitVal)
setInitializer - Sets the initializer for this global variable, removing any existing initializer if ...
CondBrInst * CreateCondBr(Value *Cond, BasicBlock *True, BasicBlock *False, MDNode *BranchWeights=nullptr, MDNode *Unpredictable=nullptr)
Create a conditional 'br Cond, TrueDest, FalseDest' instruction.
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)
Value * CreateIsNull(Value *Arg, const Twine &Name="")
Return a boolean value testing if Arg == 0.
LLVM_ABI bool isLifetimeStartOrEnd() const LLVM_READONLY
Return true if the instruction is a llvm.lifetime.start or llvm.lifetime.end marker.
LLVM_ABI bool mayWriteToMemory() const LLVM_READONLY
Return true if this instruction may modify memory.
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
LLVM_ABI bool mayHaveSideEffects() const LLVM_READONLY
Return true if the instruction may have side effects.
LLVM_ABI bool mayReadFromMemory() const LLVM_READONLY
Return true if this instruction may read memory.
iterator_range< user_iterator > users()
void setDebugLoc(DebugLoc Loc)
Set the debug location information for this instruction.
LLVM_ABI void setSuccessor(unsigned Idx, BasicBlock *BB)
Update the specified successor to point at the provided block.
LLVM_ABI const DiagnosticHandler * getDiagHandlerPtr() const
getDiagHandlerPtr - Returns const raw pointer of DiagnosticHandler set by setDiagnosticHandler.
A node in the call graph.
An SCC of the call graph.
A lazily constructed view of the call graph of a module.
const MDOperand & getOperand(unsigned I) const
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
unsigned getNumOperands() const
Return number of MDNode operands.
LLVM_ABI void eraseFromParent()
This method unlinks 'this' from the containing function and deletes it.
LLVM_ABI StringRef getName() const
Return the name of the corresponding LLVM basic block, or an empty string.
A Module instance is used to store all the information related to an LLVM module.
const Triple & getTargetTriple() const
Get the target triple which is a string describing the target host.
LLVM_ABI Constant * getOrCreateIdent(Constant *SrcLocStr, uint32_t SrcLocStrSize, omp::IdentFlag Flags=omp::IdentFlag(0), unsigned Reserve2Flags=0)
Return an ident_t* encoding the source location SrcLocStr and Flags.
LLVM_ABI FunctionCallee getOrCreateRuntimeFunction(Module &M, omp::RuntimeFunction FnID)
Return the function declaration for the runtime function with FnID.
static LLVM_ABI std::pair< int32_t, int32_t > readThreadBoundsForKernel(const Triple &T, Function &Kernel)
}
LLVM_ABI Constant * getOrCreateSrcLocStr(StringRef LocStr, uint32_t &SrcLocStrSize)
Return the (LLVM-IR) string describing the source location LocStr.
IRBuilder<>::InsertPoint InsertPointTy
Type used throughout for insertion points.
IRBuilder Builder
The LLVM-IR Builder used to create IR.
static LLVM_ABI std::pair< int32_t, int32_t > readTeamBoundsForKernel(const Triple &T, Function &Kernel)
Read/write a bounds on teams for Kernel.
bool updateToLocation(const LocationDescription &Loc)
Update the internal location to Loc.
LLVM_ABI PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG, CGSCCUpdateResult &UR)
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
static LLVM_ABI ProfileSummary * getFromMD(Metadata *MD)
Construct profile summary from metdata.
static ReturnInst * Create(LLVMContext &C, Value *retVal=nullptr, InsertPosition InsertBefore=nullptr)
A vector that has set insertion semantics.
size_type size() const
Determine the number of elements in the SetVector.
size_type count(const_arg_type key) const
Count the number of elements of a given key in the SetVector.
bool insert(const value_type &X)
Insert a new element into the SetVector.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
reference emplace_back(ArgTypes &&... Args)
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Triple - Helper class for working with autoconf configuration names.
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
LLVM_ABI unsigned getPointerAddressSpace() const
Get the address space of this pointer or pointer vector type.
static UncondBrInst * Create(BasicBlock *Target, InsertPosition InsertBefore=nullptr)
static LLVM_ABI UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
A Use represents the edge between a Value definition and its users.
LLVM_ABI bool replaceUsesOfWith(Value *From, Value *To)
Replace uses of one Value with another.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void setName(const Twine &Name)
Change the name of the value.
bool hasOneUse() const
Return true if there is exactly one use of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
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.
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
LLVM_ABI const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=MaxLookupSearchDepth, bool MustPreserveProvenance=false)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
MutableArrayRef(T &OneElt) -> MutableArrayRef< T >
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
bool operator&=(SparseBitVector< ElementSize > *LHS, const SparseBitVector< ElementSize > &RHS)
LLVM_ABI BasicBlock * SplitBlock(BasicBlock *Old, BasicBlock::iterator SplitPt, DominatorTree *DT, LoopInfo *LI=nullptr, MemorySSAUpdater *MSSAU=nullptr, const Twine &BBName="")
Split the specified block at the specified instruction.
auto count(R &&Range, const E &Element)
Wrapper function around std::count to count the number of times an element Element occurs in the give...
ArrayRef(const T &OneElt) -> ArrayRef< T >
LLVM_ABI Value * getFreedOperand(const CallBase *CB, const TargetLibraryInfo *TLI)
If this if a call to a free function, return the freed operand.
std::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
auto predecessors(const MachineBasicBlock *BB)
LLVM_ABI Constant * ConstantFoldInsertValueInstruction(Constant *Agg, Constant *Val, ArrayRef< unsigned > Idxs)
Attempt to constant fold an insertvalue instruction with the specified operands and indices.
@ OPTIONAL
The target may be valid if the source is not.
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
BumpPtrAllocatorImpl<> BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
LLVM_ABI void setFittedBranchWeights(Instruction &I, ArrayRef< uint64_t > Weights, bool IsExpected, bool ElideAllZero=false)
Variant of setBranchWeights where the Weights will be fit first to uint32_t by shifting right.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
static LLVM_ABI AAExecutionDomain & createForPosition(const IRPosition &IRP, Attributor &A)
Create an abstract attribute view for the position IRP.
AAExecutionDomain(const IRPosition &IRP, Attributor &A)
static LLVM_ABI const char ID
Unique ID (due to the unique address)
AccessKind
Simple enum to distinguish read/write/read-write accesses.
StateType::base_t MemoryLocationsKind
static LLVM_ABI bool isAlignedBarrier(const CallBase &CB, bool ExecutedAligned)
Helper function to determine if CB is an aligned (GPU) barrier.
Base struct for all "concrete attribute" deductions.
virtual const char * getIdAddr() const =0
This function should return the address of the ID of the AbstractAttribute.
An interface to query the internal state of an abstract attribute.
Wrapper for FunctionAnalysisManager.
Configuration for the Attributor.
std::function< void(Attributor &A, const Function &F)> InitializationCallback
Callback function to be invoked on internal functions marked live.
std::optional< unsigned > MaxFixpointIterations
Maximum number of iterations to run until fixpoint.
bool RewriteSignatures
Flag to determine if we rewrite function signatures.
OptimizationRemarkGetter OREGetter
IPOAmendableCBTy IPOAmendableCB
bool IsModulePass
Is the user of the Attributor a module pass or not.
std::function< bool(Attributor &A, const AbstractAttribute &AA, CallBase &CB, Function &AssumedCallee, unsigned NumAssumedCallees)> IndirectCalleeSpecializationCallback
Callback function to determine if an indirect call targets should be made direct call targets (with a...
bool DefaultInitializeLiveInternals
Flag to determine if we want to initialize all default AAs for an internal function marked live.
The fixpoint analysis framework that orchestrates the attribute deduction.
static LLVM_ABI bool isInternalizable(Function &F)
Returns true if the function F can be internalized.
std::function< std::optional< Value * >( const IRPosition &, const AbstractAttribute *, bool &)> SimplifictionCallbackTy
Register CB as a simplification callback.
std::function< std::optional< Constant * >( const GlobalVariable &, const AbstractAttribute *, bool &)> GlobalVariableSimplifictionCallbackTy
Register CB as a simplification callback.
std::function< bool(Attributor &, const AbstractAttribute *)> VirtualUseCallbackTy
static LLVM_ABI bool internalizeFunctions(SmallPtrSetImpl< Function * > &FnSet, DenseMap< Function *, Function * > &FnMap)
Make copies of each function in the set FnSet such that the copied version has internal linkage after...
Simple wrapper for a single bit (boolean) state.
Support structure for SCC passes to communicate updates the call graph back to the CGSCC pass manager...
bool isAnyRemarkEnabled(StringRef PassName) const
Return true if any type of remarks are enabled for this pass.
Helper to describe and deal with positions in the LLVM-IR.
static const IRPosition callsite_returned(const CallBase &CB)
Create a position describing the returned value of CB.
static const IRPosition returned(const Function &F, const CallBaseContext *CBContext=nullptr)
Create a position describing the returned value of F.
static const IRPosition value(const Value &V, const CallBaseContext *CBContext=nullptr)
Create a position describing the value of V.
static const IRPosition inst(const Instruction &I, const CallBaseContext *CBContext=nullptr)
Create a position describing the instruction I.
@ IRP_ARGUMENT
An attribute for a function argument.
@ IRP_RETURNED
An attribute for the function return value.
@ IRP_CALL_SITE
An attribute for a call site (function scope).
@ IRP_CALL_SITE_RETURNED
An attribute for a call site return value.
@ IRP_FUNCTION
An attribute for a function (scope).
@ IRP_FLOAT
A position that is not associated with a spot suitable for attributes.
@ IRP_CALL_SITE_ARGUMENT
An attribute for a call site argument.
@ IRP_INVALID
An invalid position.
static const IRPosition function(const Function &F, const CallBaseContext *CBContext=nullptr)
Create a position describing the function scope of F.
Kind getPositionKind() const
Return the associated position kind.
static const IRPosition callsite_function(const CallBase &CB)
Create a position describing the function scope of CB.
Defines various target-specific GPU grid values that must be consistent between host RTL (plugin),...