51#include "llvm/IR/IntrinsicsAMDGPU.h"
52#include "llvm/IR/IntrinsicsNVPTX.h"
74#define DEBUG_TYPE "openmp-opt"
77 "openmp-opt-disable",
cl::desc(
"Disable OpenMP specific optimizations."),
81 "openmp-opt-enable-merging",
87 cl::desc(
"Disable function internalization."),
98 "openmp-hide-memory-transfer-latency",
99 cl::desc(
"[WIP] Tries to hide the latency of host to device memory"
104 "openmp-opt-disable-deglobalization",
105 cl::desc(
"Disable OpenMP optimizations involving deglobalization."),
109 "openmp-opt-disable-spmdization",
110 cl::desc(
"Disable OpenMP optimizations involving SPMD-ization."),
114 "openmp-opt-disable-folding",
119 "openmp-opt-disable-state-machine-rewrite",
120 cl::desc(
"Disable OpenMP optimizations that replace the state machine."),
124 "openmp-opt-disable-barrier-elimination",
125 cl::desc(
"Disable OpenMP optimizations that eliminate barriers."),
129 "openmp-opt-print-module-after",
130 cl::desc(
"Print the current module after OpenMP optimizations."),
134 "openmp-opt-print-module-before",
135 cl::desc(
"Print the current module before OpenMP optimizations."),
139 "openmp-opt-inline-device",
150 cl::desc(
"Maximal number of attributor iterations."),
155 cl::desc(
"Maximum amount of shared memory to use."),
156 cl::init(std::numeric_limits<unsigned>::max()));
159 "openmp-opt-max-callees-for-specialization",
cl::Hidden,
160 cl::desc(
"Number of possible callees above which an indirect call site is "
161 "left alone rather than specialized into an if-cascade."),
165 "Number of OpenMP runtime calls deduplicated");
167 "Number of OpenMP parallel regions deleted");
169 "Number of OpenMP runtime functions identified");
171 "Number of OpenMP runtime function uses identified");
173 "Number of OpenMP target region entry points (=kernels) identified");
175 "Number of non-OpenMP target region kernels identified");
177 "Number of OpenMP target region entry points (=kernels) executed in "
178 "SPMD-mode instead of generic-mode");
179STATISTIC(NumOpenMPTargetRegionKernelsWithoutStateMachine,
180 "Number of OpenMP target region entry points (=kernels) executed in "
181 "generic-mode without a state machines");
182STATISTIC(NumOpenMPTargetRegionKernelsCustomStateMachineWithFallback,
183 "Number of OpenMP target region entry points (=kernels) executed in "
184 "generic-mode with customized state machines with fallback");
185STATISTIC(NumOpenMPTargetRegionKernelsCustomStateMachineWithoutFallback,
186 "Number of OpenMP target region entry points (=kernels) executed in "
187 "generic-mode with customized state machines without fallback");
189 NumOpenMPParallelRegionsReplacedInGPUStateMachine,
190 "Number of OpenMP parallel regions replaced with ID in GPU state machines");
192 "Number of OpenMP parallel regions merged");
194 "Amount of memory pushed to shared memory");
195STATISTIC(NumBarriersEliminated,
"Number of redundant barriers eliminated");
223#define KERNEL_ENVIRONMENT_IDX(MEMBER, IDX) \
224 constexpr unsigned MEMBER##Idx = IDX;
229#undef KERNEL_ENVIRONMENT_IDX
231#define KERNEL_ENVIRONMENT_CONFIGURATION_IDX(MEMBER, IDX) \
232 constexpr unsigned MEMBER##Idx = IDX;
242#undef KERNEL_ENVIRONMENT_CONFIGURATION_IDX
244#define KERNEL_ENVIRONMENT_GETTER(MEMBER, RETURNTYPE) \
245 RETURNTYPE *get##MEMBER##FromKernelEnvironment(ConstantStruct *KernelEnvC) { \
246 return cast<RETURNTYPE>(KernelEnvC->getAggregateElement(MEMBER##Idx)); \
252#undef KERNEL_ENVIRONMENT_GETTER
254#define KERNEL_ENVIRONMENT_CONFIGURATION_GETTER(MEMBER) \
255 ConstantInt *get##MEMBER##FromKernelEnvironment( \
256 ConstantStruct *KernelEnvC) { \
257 ConstantStruct *ConfigC = \
258 getConfigurationFromKernelEnvironment(KernelEnvC); \
259 return dyn_cast<ConstantInt>(ConfigC->getAggregateElement(MEMBER##Idx)); \
270#undef KERNEL_ENVIRONMENT_CONFIGURATION_GETTER
274 constexpr int InitKernelEnvironmentArgNo = 0;
289struct AAHeapToShared;
296 OMPInformationCache(
Module &M, AnalysisGetter &AG,
300 OpenMPPostLink(OpenMPPostLink) {
303 const Triple
T(OMPBuilder.M.getTargetTriple());
304 switch (
T.getArch()) {
308 assert(OMPBuilder.Config.IsTargetDevice &&
309 "OpenMP AMDGPU/NVPTX is only prepared to deal with device code.");
310 OMPBuilder.Config.IsGPU =
true;
313 OMPBuilder.Config.IsGPU =
false;
316 OMPBuilder.initialize();
317 initializeRuntimeFunctions(M);
318 initializeInternalControlVars();
322 struct InternalControlVarInfo {
330 StringRef EnvVarName;
336 ConstantInt *InitValue;
349 struct RuntimeFunctionInfo {
370 using UseVector = SmallVector<Use *, 16>;
373 void clearUsesMap() { UsesMap.clear(); }
376 operator bool()
const {
return Declaration; }
379 UseVector &getOrCreateUseVector(
Function *
F) {
380 std::shared_ptr<UseVector> &UV = UsesMap[
F];
382 UV = std::make_shared<UseVector>();
388 const UseVector *getUseVector(
Function &
F)
const {
389 auto I = UsesMap.find(&
F);
390 if (
I != UsesMap.end())
391 return I->second.get();
396 size_t getNumFunctionsWithUses()
const {
return UsesMap.size(); }
400 size_t getNumArgs()
const {
return ArgumentTypes.size(); }
405 void foreachUse(SmallVectorImpl<Function *> &SCC,
406 function_ref<
bool(Use &,
Function &)> CB) {
414 SmallVector<unsigned, 8> ToBeDeleted;
418 UseVector &UV = getOrCreateUseVector(
F);
428 while (!ToBeDeleted.
empty()) {
438 DenseMap<Function *, std::shared_ptr<UseVector>> UsesMap;
442 decltype(UsesMap)::iterator
begin() {
return UsesMap.begin(); }
443 decltype(UsesMap)::iterator
end() {
return UsesMap.end(); }
447 OpenMPIRBuilder OMPBuilder;
451 RuntimeFunction::OMPRTL___last>
455 DenseMap<Function *, RuntimeFunction> RuntimeFunctionIDMap;
459 InternalControlVar::ICV___last>
464 void initializeInternalControlVars() {
465#define ICV_RT_SET(_Name, RTL) \
467 auto &ICV = ICVs[_Name]; \
470#define ICV_RT_GET(Name, RTL) \
472 auto &ICV = ICVs[Name]; \
475#define ICV_DATA_ENV(Enum, _Name, _EnvVarName, Init) \
477 auto &ICV = ICVs[Enum]; \
480 ICV.InitKind = Init; \
481 ICV.EnvVarName = _EnvVarName; \
482 switch (ICV.InitKind) { \
483 case ICV_IMPLEMENTATION_DEFINED: \
484 ICV.InitValue = nullptr; \
487 ICV.InitValue = ConstantInt::get( \
488 Type::getInt32Ty(OMPBuilder.Int32->getContext()), 0); \
491 ICV.InitValue = ConstantInt::getFalse(OMPBuilder.Int1->getContext()); \
497#include "llvm/Frontend/OpenMP/OMPKinds.def"
503 static bool declMatchesRTFTypes(
Function *
F,
Type *RTFRetType,
510 if (
F->getReturnType() != RTFRetType)
512 if (
F->arg_size() != RTFArgTypes.
size())
515 auto *RTFTyIt = RTFArgTypes.
begin();
516 for (Argument &Arg :
F->args()) {
517 if (Arg.getType() != *RTFTyIt)
527 unsigned collectUses(RuntimeFunctionInfo &RFI,
bool CollectStats =
true) {
528 unsigned NumUses = 0;
529 if (!RFI.Declaration)
531 OMPBuilder.addAttributes(RFI.Kind, *RFI.Declaration);
534 NumOpenMPRuntimeFunctionsIdentified += 1;
535 NumOpenMPRuntimeFunctionUsesIdentified += RFI.Declaration->getNumUses();
539 for (Use &U : RFI.Declaration->uses()) {
541 if (!
CGSCC ||
CGSCC->empty() ||
CGSCC->contains(UserI->getFunction())) {
542 RFI.getOrCreateUseVector(UserI->getFunction()).push_back(&U);
546 RFI.getOrCreateUseVector(
nullptr).push_back(&U);
555 auto &RFI = RFIs[RTF];
557 collectUses(RFI,
false);
565 void setCallbackMetadata(
Function *
F,
unsigned ArgNo, ArrayRef<int> Indices,
567 if (!
F ||
F->hasMetadata(LLVMContext::MD_callback))
570 LLVMContext &Ctx =
F->getContext();
572 F->addMetadata(LLVMContext::MD_callback,
573 *
MDNode::get(Ctx, {MDB.createCallbackEncoding(ArgNo, Indices,
581 static Function *getAnalyzableCallback(
const CallBase &CB) {
585 MDNode *CallbackMD =
Callee->getMetadata(LLVMContext::MD_callback);
591 if (!Encoding || Encoding->getNumOperands() == 0)
602 if (!Callback ||
Callback->isDeclaration())
608 void recollectUses() {
609 for (
int Idx = 0;
Idx < RFIs.size(); ++
Idx)
614 void setCallingConvention(FunctionCallee Callee, CallInst *CI) {
629 RuntimeFunctionInfo &RFI = RFIs[Fn];
631 if (!RFI.Declaration || RFI.Declaration->isDeclaration())
639 void initializeRuntimeFunctions(
Module &M) {
642#define OMP_TYPE(VarName, ...) \
643 Type *VarName = OMPBuilder.VarName; \
646#define OMP_ARRAY_TYPE(VarName, ...) \
647 ArrayType *VarName##Ty = OMPBuilder.VarName##Ty; \
649 PointerType *VarName##PtrTy = OMPBuilder.VarName##PtrTy; \
650 (void)VarName##PtrTy;
652#define OMP_FUNCTION_TYPE(VarName, ...) \
653 FunctionType *VarName = OMPBuilder.VarName; \
655 PointerType *VarName##Ptr = OMPBuilder.VarName##Ptr; \
658#define OMP_STRUCT_TYPE(VarName, ...) \
659 StructType *VarName = OMPBuilder.VarName; \
661 PointerType *VarName##Ptr = OMPBuilder.VarName##Ptr; \
664#define OMP_RTL(_Enum, _Name, _IsVarArg, _ReturnType, ...) \
666 SmallVector<Type *, 8> ArgsTypes({__VA_ARGS__}); \
667 Function *F = M.getFunction(_Name); \
668 RTLFunctions.insert(F); \
669 if (declMatchesRTFTypes(F, OMPBuilder._ReturnType, ArgsTypes)) { \
670 RuntimeFunctionIDMap[F] = _Enum; \
671 auto &RFI = RFIs[_Enum]; \
674 RFI.IsVarArg = _IsVarArg; \
675 RFI.ReturnType = OMPBuilder._ReturnType; \
676 RFI.ArgumentTypes = std::move(ArgsTypes); \
677 RFI.Declaration = F; \
678 unsigned NumUses = collectUses(RFI); \
681 dbgs() << TAG << RFI.Name << (RFI.Declaration ? "" : " not") \
683 if (RFI.Declaration) \
684 dbgs() << TAG << "-> got " << NumUses << " uses in " \
685 << RFI.getNumFunctionsWithUses() \
686 << " different functions.\n"; \
691#define OMP_RTL_CB_INFO(_Enum, _Name, _ArgNo, _ArgIndices, _IsVarArg) \
692 setCallbackMetadata(M.getFunction(_Name), _ArgNo, _ArgIndices, _IsVarArg);
694#include "llvm/Frontend/OpenMP/OMPKinds.def"
700 for (StringRef Prefix : {
"__kmpc",
"_ZN4ompx",
"omp_"})
701 if (
F.hasFnAttribute(Attribute::NoInline) &&
702 F.getName().starts_with(Prefix) &&
703 !
F.hasFnAttribute(Attribute::OptimizeNone))
704 F.removeFnAttr(Attribute::NoInline);
712 DenseSet<const Function *> RTLFunctions;
715 bool OpenMPPostLink =
false;
722 SmallPtrSet<Function *, 8> SPMDizedKernels;
725template <
typename Ty,
bool InsertInval
idates = true>
727 bool contains(
const Ty &Elem)
const {
return Set.contains(Elem); }
728 bool insert(
const Ty &Elem) {
729 if (InsertInvalidates)
730 BooleanState::indicatePessimisticFixpoint();
731 return Set.insert(Elem);
734 const Ty &operator[](
int Idx)
const {
return Set[
Idx]; }
735 bool operator==(
const BooleanStateWithSetVector &
RHS)
const {
736 return BooleanState::operator==(
RHS) && Set ==
RHS.Set;
738 bool operator!=(
const BooleanStateWithSetVector &
RHS)
const {
739 return !(*
this ==
RHS);
742 bool empty()
const {
return Set.empty(); }
743 size_t size()
const {
return Set.size(); }
746 BooleanStateWithSetVector &
operator^=(
const BooleanStateWithSetVector &
RHS) {
747 BooleanState::operator^=(
RHS);
748 Set.insert_range(
RHS.Set);
757 typename decltype(Set)::iterator
begin() {
return Set.begin(); }
758 typename decltype(Set)::iterator
end() {
return Set.end(); }
759 typename decltype(Set)::const_iterator
begin()
const {
return Set.begin(); }
760 typename decltype(Set)::const_iterator
end()
const {
return Set.end(); }
763template <
typename Ty,
bool InsertInval
idates = true>
764using BooleanStateWithPtrSetVector =
765 BooleanStateWithSetVector<Ty *, InsertInvalidates>;
769 bool IsAtFixpoint =
false;
773 BooleanStateWithPtrSetVector<CallBase,
false>
774 ReachedKnownParallelRegions;
777 BooleanStateWithPtrSetVector<CallBase> ReachedUnknownParallelRegions;
782 BooleanStateWithPtrSetVector<Instruction, false> SPMDCompatibilityTracker;
786 CallBase *KernelInitCB =
nullptr;
790 ConstantStruct *KernelEnvC =
nullptr;
794 CallBase *KernelDeinitCB =
nullptr;
797 bool IsKernelEntry =
false;
800 BooleanStateWithPtrSetVector<Function, false> ReachingKernelEntries;
805 BooleanStateWithSetVector<uint8_t> ParallelLevels;
808 bool NestedParallelism =
false;
813 KernelInfoState() =
default;
814 KernelInfoState(
bool BestState) {
816 indicatePessimisticFixpoint();
819 bool isValidState()
const override {
return true; }
821 bool isAtFixpoint()
const override {
return IsAtFixpoint; }
825 ParallelLevels.indicatePessimisticFixpoint();
826 ReachingKernelEntries.indicatePessimisticFixpoint();
827 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
828 ReachedKnownParallelRegions.indicatePessimisticFixpoint();
829 ReachedUnknownParallelRegions.indicatePessimisticFixpoint();
830 NestedParallelism =
true;
831 return ChangeStatus::CHANGED;
836 ParallelLevels.indicateOptimisticFixpoint();
837 ReachingKernelEntries.indicateOptimisticFixpoint();
838 SPMDCompatibilityTracker.indicateOptimisticFixpoint();
839 ReachedKnownParallelRegions.indicateOptimisticFixpoint();
840 ReachedUnknownParallelRegions.indicateOptimisticFixpoint();
841 return ChangeStatus::UNCHANGED;
845 KernelInfoState &getAssumed() {
return *
this; }
846 const KernelInfoState &getAssumed()
const {
return *
this; }
849 if (SPMDCompatibilityTracker !=
RHS.SPMDCompatibilityTracker)
851 if (ReachedKnownParallelRegions !=
RHS.ReachedKnownParallelRegions)
853 if (ReachedUnknownParallelRegions !=
RHS.ReachedUnknownParallelRegions)
855 if (ReachingKernelEntries !=
RHS.ReachingKernelEntries)
857 if (ParallelLevels !=
RHS.ParallelLevels)
859 if (NestedParallelism !=
RHS.NestedParallelism)
865 bool mayContainParallelRegion() {
866 return !ReachedKnownParallelRegions.empty() ||
867 !ReachedUnknownParallelRegions.empty();
871 static KernelInfoState getBestState() {
return KernelInfoState(
true); }
873 static KernelInfoState getBestState(KernelInfoState &KIS) {
874 return getBestState();
878 static KernelInfoState getWorstState() {
return KernelInfoState(
false); }
881 KernelInfoState
operator^=(
const KernelInfoState &KIS) {
883 if (KIS.KernelInitCB) {
884 if (KernelInitCB && KernelInitCB != KIS.KernelInitCB)
887 KernelInitCB = KIS.KernelInitCB;
889 if (KIS.KernelDeinitCB) {
890 if (KernelDeinitCB && KernelDeinitCB != KIS.KernelDeinitCB)
893 KernelDeinitCB = KIS.KernelDeinitCB;
895 if (KIS.KernelEnvC) {
896 if (KernelEnvC && KernelEnvC != KIS.KernelEnvC)
899 KernelEnvC = KIS.KernelEnvC;
901 SPMDCompatibilityTracker ^= KIS.SPMDCompatibilityTracker;
902 ReachedKnownParallelRegions ^= KIS.ReachedKnownParallelRegions;
903 ReachedUnknownParallelRegions ^= KIS.ReachedUnknownParallelRegions;
904 NestedParallelism |= KIS.NestedParallelism;
908 KernelInfoState
operator&=(
const KernelInfoState &KIS) {
909 return (*
this ^= KIS);
919 AllocaInst *Array =
nullptr;
921 SmallVector<Value *, 8> StoredValues;
923 SmallVector<StoreInst *, 8> LastAccesses;
925 OffloadArray() =
default;
931 bool initialize(AllocaInst &Array, Instruction &Before) {
932 if (!getValues(Array, Before))
935 this->Array = &Array;
939 static const unsigned DeviceIDArgNum = 1;
940 static const unsigned BasePtrsArgNum = 3;
941 static const unsigned PtrsArgNum = 4;
942 static const unsigned SizesArgNum = 5;
948 bool getValues(AllocaInst &Array, Instruction &Before) {
950 const DataLayout &
DL = Array.getDataLayout();
951 std::optional<TypeSize> ArraySize = Array.getAllocationSize(
DL);
952 if (!ArraySize || !ArraySize->isFixed())
956 StoredValues.assign(NumValues,
nullptr);
957 LastAccesses.assign(NumValues,
nullptr);
965 for (Instruction &
I : *BB) {
981 LastAccesses[
Idx] = S;
992 const unsigned NumValues = StoredValues.size();
993 for (
unsigned I = 0;
I < NumValues; ++
I) {
994 if (!StoredValues[
I] || !LastAccesses[
I])
1005static std::optional<uint64_t>
1007 unsigned CallbackOpNo) {
1008 std::optional<uint64_t> EntryCount;
1014 if (std::optional<uint64_t> EC =
Callback->getEntryCount())
1017 EntryCount = EntryCount ? std::max(*EntryCount, *EC) : *
EC;
1022static bool moduleHasSampleProfile(
const Module &M) {
1023 std::unique_ptr<ProfileSummary> Summary(
1030 using OptimizationRemarkGetter =
1031 function_ref<OptimizationRemarkEmitter &(
Function *)>;
1033 OpenMPOpt(SmallVectorImpl<Function *> &SCC, CallGraphUpdater &CGUpdater,
1034 OptimizationRemarkGetter OREGetter,
1035 OMPInformationCache &OMPInfoCache, Attributor &A)
1036 : M(*(*SCC.
begin())->
getParent()), SCC(SCC), CGUpdater(CGUpdater),
1037 OREGetter(OREGetter), OMPInfoCache(OMPInfoCache), A(A) {}
1040 bool remarksEnabled() {
1041 auto &Ctx = M.getContext();
1046 bool run(
bool IsModulePass) {
1056 Changed |= runAttributor(IsModulePass);
1059 OMPInfoCache.recollectUses();
1062 Changed |= rewriteDeviceCodeStateMachine();
1068 Changed |= removeSPMDParallelWrappers();
1070 if (remarksEnabled())
1071 analysisGlobalization();
1078 Changed |= runAttributor(IsModulePass);
1081 OMPInfoCache.recollectUses();
1083 Changed |= deleteParallelRegions();
1086 Changed |= hideMemTransfersLatency();
1087 Changed |= deduplicateRuntimeCalls();
1089 if (mergeParallelRegions()) {
1090 deduplicateRuntimeCalls();
1096 if (OMPInfoCache.OpenMPPostLink)
1097 Changed |= removeRuntimeSymbols();
1104 void printICVs()
const {
1109 for (
auto ICV : ICVs) {
1110 auto ICVInfo = OMPInfoCache.ICVs[ICV];
1111 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
1112 return ORA <<
"OpenMP ICV " <<
ore::NV(
"OpenMPICV", ICVInfo.Name)
1114 << (ICVInfo.InitValue
1115 ?
toString(ICVInfo.InitValue->getValue(), 10,
true)
1116 :
"IMPLEMENTATION_DEFINED");
1125 void printKernels()
const {
1130 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
1131 return ORA <<
"OpenMP GPU kernel "
1132 <<
ore::NV(
"OpenMPGPUKernel",
F->getName()) <<
"\n";
1141 static CallInst *getCallIfRegularCall(
1142 Use &U, OMPInformationCache::RuntimeFunctionInfo *RFI =
nullptr) {
1153 static CallInst *getCallIfRegularCall(
1154 Value &V, OMPInformationCache::RuntimeFunctionInfo *RFI =
nullptr) {
1165 bool mergeParallelRegions() {
1166 const unsigned CallbackCalleeOperand = 2;
1167 const unsigned CallbackFirstArgOperand = 3;
1171 OMPInformationCache::RuntimeFunctionInfo &RFI =
1172 OMPInfoCache.RFIs[OMPRTL___kmpc_fork_call];
1174 if (!RFI.Declaration)
1178 OMPInformationCache::RuntimeFunctionInfo UnmergableCallsInfo[] = {
1179 OMPInfoCache.RFIs[OMPRTL___kmpc_push_proc_bind],
1180 OMPInfoCache.RFIs[OMPRTL___kmpc_push_num_threads],
1184 LoopInfo *LI =
nullptr;
1185 DominatorTree *DT =
nullptr;
1187 SmallDenseMap<BasicBlock *, SmallPtrSet<Instruction *, 4>> BB2PRMap;
1189 BasicBlock *StartBB =
nullptr, *EndBB =
nullptr;
1190 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
1192 BasicBlock *CGStartBB = CodeGenIP.getNodeParent();
1194 assert(StartBB !=
nullptr &&
"StartBB should not be null");
1196 assert(EndBB !=
nullptr &&
"EndBB should not be null");
1197 EndBB->getTerminator()->setSuccessor(0, CGEndBB);
1201 auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
Value &,
1202 Value &Inner,
Value *&ReplacementValue) -> InsertPointTy {
1203 ReplacementValue = &Inner;
1207 auto FiniCB = [&](InsertPointTy CodeGenIP) {
return Error::success(); };
1211 auto CreateSequentialRegion = [&](
Function *OuterFn,
1217 BasicBlock *ParentBB = SeqStartI->getParent();
1219 SplitBlock(ParentBB, SeqEndI->getNextNode(), DT, LI);
1223 SplitBlock(ParentBB, SeqStartI, DT, LI,
nullptr,
"seq.par.merged");
1226 "Expected a different CFG");
1230 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
1232 BasicBlock *CGStartBB = CodeGenIP.getNodeParent();
1234 assert(SeqStartBB !=
nullptr &&
"SeqStartBB should not be null");
1236 assert(SeqEndBB !=
nullptr &&
"SeqEndBB should not be null");
1240 auto FiniCB = [&](InsertPointTy CodeGenIP) {
return Error::success(); };
1244 for (Instruction &
I : *SeqStartBB) {
1245 SmallPtrSet<Instruction *, 4> OutsideUsers;
1246 for (User *Usr :
I.users()) {
1254 OutsideUsers.
insert(&UsrI);
1257 if (OutsideUsers.
empty())
1262 const DataLayout &
DL = M.getDataLayout();
1263 AllocaInst *AllocaI =
new AllocaInst(
1264 I.getType(),
DL.getAllocaAddrSpace(),
nullptr,
1269 new StoreInst(&
I, AllocaI, SeqStartBB->getTerminator()->getIterator());
1273 for (Instruction *UsrI : OutsideUsers) {
1274 LoadInst *LoadI =
new LoadInst(
I.getType(), AllocaI,
1275 I.getName() +
".seq.output.load",
1281 OpenMPIRBuilder::LocationDescription Loc(ParentBB->
end(),
DL);
1283 OMPInfoCache.OMPBuilder.createMaster(Loc, BodyGenCB, FiniCB));
1284 cantFail(OMPInfoCache.OMPBuilder.createBarrier({SeqAfterIP, DL},
1300 auto Merge = [&](
const SmallVectorImpl<CallInst *> &MergableCIs,
1304 assert(MergableCIs.
size() > 1 &&
"Assumed multiple mergable CIs");
1306 auto Remark = [&](OptimizationRemark
OR) {
1307 OR <<
"Parallel region merged with parallel region"
1308 << (MergableCIs.
size() > 2 ?
"s" :
"") <<
" at ";
1311 if (CI != MergableCIs.
back())
1319 Function *OriginalFn = BB->getParent();
1321 <<
" parallel regions in " << OriginalFn->
getName()
1325 EndBB =
SplitBlock(BB, MergableCIs.
back()->getNextNode(), DT, LI);
1327 SplitBlock(EndBB, &*EndBB->getFirstInsertionPt(), DT, LI);
1331 assert(BB->getUniqueSuccessor() == StartBB &&
"Expected a different CFG");
1332 const DebugLoc DL = BB->getTerminator()->getDebugLoc();
1337 for (
auto *It = MergableCIs.
begin(), *
End = MergableCIs.
end() - 1;
1346 CreateSequentialRegion(OriginalFn, BB, ForkCI->
getNextNode(),
1350 OpenMPIRBuilder::LocationDescription Loc(BB->end(),
DL);
1351 IRBuilder<>::InsertPoint AllocaIP(
1356 cantFail(OMPInfoCache.OMPBuilder.createParallel(
1357 Loc, AllocaIP, {}, BodyGenCB, PrivCB, FiniCB,
1358 nullptr,
nullptr, OMP_PROC_BIND_default,
1363 OMPInfoCache.OMPBuilder.finalize(OriginalFn);
1366 std::optional<uint64_t> WrapperCount =
1367 getMergedWrapperEntryCount(MergableCIs, CallbackCalleeOperand);
1373 const bool SampleProfile =
1374 moduleHasSampleProfile(*OriginalFn->
getParent());
1378 SmallVector<Value *, 8>
Args;
1379 for (
auto *CI : MergableCIs) {
1381 FunctionType *FT = OMPInfoCache.OMPBuilder.ParallelTask;
1385 for (
unsigned U = CallbackFirstArgOperand,
E = CI->
arg_size(); U <
E;
1395 if (WrapperCount && SampleProfile) {
1401 for (
unsigned U = CallbackFirstArgOperand,
E = CI->
arg_size(); U <
E;
1405 U - (CallbackFirstArgOperand - CallbackCalleeOperand), A);
1408 if (CI != MergableCIs.back()) {
1411 cantFail(OMPInfoCache.OMPBuilder.createBarrier(
1412 {NewCI->getNextNode()->getIterator(), NewCI->getDebugLoc()},
1419 assert(OutlinedFn != OriginalFn &&
"Outlining failed");
1420 CGUpdater.registerOutlinedFunction(*OriginalFn, *OutlinedFn);
1421 CGUpdater.reanalyzeFunction(*OriginalFn);
1423 NumOpenMPParallelRegionsMerged += MergableCIs.size();
1431 CallInst *CI = getCallIfRegularCall(U, &RFI);
1438 RFI.foreachUse(SCC, DetectPRsCB);
1444 for (
auto &It : BB2PRMap) {
1445 auto &CIs = It.getSecond();
1460 auto IsMergable = [&](
Instruction &
I,
bool IsBeforeMergableRegion) {
1463 if (
I.isTerminator())
1470 if (IsBeforeMergableRegion) {
1472 if (!CalledFunction)
1479 for (
const auto &RFI : UnmergableCallsInfo) {
1480 if (CalledFunction == RFI.Declaration)
1499 if (CIs.count(&
I)) {
1505 if (IsMergable(
I, MergableCIs.
empty()))
1510 for (; It !=
End; ++It) {
1512 if (CIs.count(&SkipI)) {
1514 <<
" due to " <<
I <<
"\n");
1521 if (MergableCIs.
size() > 1) {
1522 MergableCIsVector.
push_back(MergableCIs);
1524 <<
" parallel regions in block " << BB->
getName()
1529 MergableCIs.
clear();
1532 if (!MergableCIsVector.
empty()) {
1535 for (
auto &MergableCIs : MergableCIsVector)
1536 Merge(MergableCIs, BB);
1537 MergableCIsVector.clear();
1544 OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_fork_call);
1545 OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_barrier);
1546 OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_master);
1547 OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_end_master);
1554 bool deleteParallelRegions() {
1555 const unsigned CallbackCalleeOperand = 2;
1557 OMPInformationCache::RuntimeFunctionInfo &RFI =
1558 OMPInfoCache.RFIs[OMPRTL___kmpc_fork_call];
1560 if (!RFI.Declaration)
1565 CallInst *CI = getCallIfRegularCall(U);
1572 if (!Fn->onlyReadsMemory())
1574 if (!Fn->hasFnAttribute(Attribute::WillReturn))
1580 auto Remark = [&](OptimizationRemark
OR) {
1581 return OR <<
"Removing parallel region with no side-effects.";
1587 ++NumOpenMPParallelRegionsDeleted;
1591 RFI.foreachUse(SCC, DeleteCallCB);
1597 bool deduplicateRuntimeCalls() {
1601 OMPRTL_omp_get_num_threads,
1602 OMPRTL_omp_in_parallel,
1603 OMPRTL_omp_get_cancellation,
1604 OMPRTL_omp_get_supported_active_levels,
1605 OMPRTL_omp_get_level,
1606 OMPRTL_omp_get_ancestor_thread_num,
1607 OMPRTL_omp_get_team_size,
1608 OMPRTL_omp_get_active_level,
1609 OMPRTL_omp_in_final,
1610 OMPRTL_omp_get_proc_bind,
1611 OMPRTL_omp_get_num_places,
1612 OMPRTL_omp_get_num_procs,
1613 OMPRTL_omp_get_place_num,
1614 OMPRTL_omp_get_partition_num_places,
1615 OMPRTL_omp_get_partition_place_nums};
1618 SmallSetVector<Value *, 16> GTIdArgs;
1619 collectGlobalThreadIdArguments(GTIdArgs);
1621 <<
" global thread ID arguments\n");
1624 for (
auto DeduplicableRuntimeCallID : DeduplicableRuntimeCallIDs)
1625 Changed |= deduplicateRuntimeCalls(
1626 *
F, OMPInfoCache.RFIs[DeduplicableRuntimeCallID]);
1630 Value *GTIdArg =
nullptr;
1631 for (Argument &Arg :
F->args())
1632 if (GTIdArgs.
count(&Arg)) {
1636 Changed |= deduplicateRuntimeCalls(
1637 *
F, OMPInfoCache.RFIs[OMPRTL___kmpc_global_thread_num], GTIdArg);
1644 bool removeRuntimeSymbols() {
1649 if (GlobalVariable *GV = M.getNamedGlobal(
"__llvm_rpc_client")) {
1650 if (GV->hasNUsesOrMore(1))
1654 GV->eraseFromParent();
1666 bool hideMemTransfersLatency() {
1667 auto &RFI = OMPInfoCache.RFIs[OMPRTL___tgt_target_data_begin_mapper];
1670 auto *RTCall = getCallIfRegularCall(U, &RFI);
1674 OffloadArray OffloadArrays[3];
1675 if (!getValuesInOffloadArrays(*RTCall, OffloadArrays))
1678 LLVM_DEBUG(dumpValuesInOffloadArrays(OffloadArrays));
1681 bool WasSplit =
false;
1682 Instruction *WaitMovementPoint = canBeMovedDownwards(*RTCall);
1683 if (WaitMovementPoint)
1684 WasSplit = splitTargetDataBeginRTC(*RTCall, *WaitMovementPoint);
1689 if (OMPInfoCache.runtimeFnsAvailable(
1690 {OMPRTL___tgt_target_data_begin_mapper_issue,
1691 OMPRTL___tgt_target_data_begin_mapper_wait}))
1692 RFI.foreachUse(SCC, SplitMemTransfers);
1697 void analysisGlobalization() {
1698 auto &RFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
1700 auto CheckGlobalization = [&](
Use &
U,
Function &Decl) {
1701 if (CallInst *CI = getCallIfRegularCall(U, &RFI)) {
1702 auto Remark = [&](OptimizationRemarkMissed ORM) {
1704 <<
"Found thread data sharing on the GPU. "
1705 <<
"Expect degraded performance due to data globalization.";
1713 RFI.foreachUse(SCC, CheckGlobalization);
1718 bool getValuesInOffloadArrays(CallInst &RuntimeCall,
1720 assert(OAs.
size() == 3 &&
"Need space for three offload arrays!");
1730 Value *BasePtrsArg =
1742 if (!OAs[0].
initialize(*BasePtrsArray, RuntimeCall))
1750 if (!OAs[1].
initialize(*PtrsArray, RuntimeCall))
1762 if (!OAs[2].
initialize(*SizesArray, RuntimeCall))
1773 assert(OAs.
size() == 3 &&
"There are three offload arrays to debug!");
1776 std::string ValuesStr;
1777 raw_string_ostream
Printer(ValuesStr);
1778 std::string Separator =
" --- ";
1780 for (
auto *BP : OAs[0].StoredValues) {
1784 LLVM_DEBUG(
dbgs() <<
"\t\toffload_baseptrs: " << ValuesStr <<
"\n");
1787 for (
auto *
P : OAs[1].StoredValues) {
1794 for (
auto *S : OAs[2].StoredValues) {
1798 LLVM_DEBUG(
dbgs() <<
"\t\toffload_sizes: " << ValuesStr <<
"\n");
1803 Instruction *canBeMovedDownwards(CallInst &RuntimeCall) {
1808 bool IsWorthIt =
false;
1827 return RuntimeCall.
getParent()->getTerminator();
1831 bool splitTargetDataBeginRTC(CallInst &RuntimeCall,
1832 Instruction &WaitMovementPoint) {
1836 auto &
IRBuilder = OMPInfoCache.OMPBuilder;
1839 IRBuilder.Builder.SetInsertPoint(
Entry.getFirstNonPHIOrAlloca());
1841 IRBuilder.AsyncInfo,
nullptr,
"handle");
1848 FunctionCallee IssueDecl =
IRBuilder.getOrCreateRuntimeFunction(
1849 M, OMPRTL___tgt_target_data_begin_mapper_issue);
1852 SmallVector<Value *, 16>
Args;
1853 for (
auto &Arg : RuntimeCall.
args())
1854 Args.push_back(Arg.get());
1855 Args.push_back(Handle);
1859 OMPInfoCache.setCallingConvention(IssueDecl, IssueCallsite);
1864 FunctionCallee WaitDecl =
IRBuilder.getOrCreateRuntimeFunction(
1865 M, OMPRTL___tgt_target_data_begin_mapper_wait);
1867 Value *WaitParams[2] = {
1869 OffloadArray::DeviceIDArgNum),
1873 WaitDecl, WaitParams,
"", WaitMovementPoint.
getIterator());
1874 OMPInfoCache.setCallingConvention(WaitDecl, WaitCallsite);
1879 static Value *combinedIdentStruct(
Value *CurrentIdent,
Value *NextIdent,
1880 bool GlobalOnly,
bool &SingleChoice) {
1881 if (CurrentIdent == NextIdent)
1882 return CurrentIdent;
1887 SingleChoice = !CurrentIdent;
1899 getCombinedIdentFromCallUsesIn(OMPInformationCache::RuntimeFunctionInfo &RFI,
1901 bool SingleChoice =
true;
1902 Value *Ident =
nullptr;
1904 CallInst *CI = getCallIfRegularCall(U, &RFI);
1905 if (!CI || &
F != &Caller)
1908 true, SingleChoice);
1911 RFI.foreachUse(SCC, CombineIdentStruct);
1913 if (!Ident || !SingleChoice) {
1917 if (!OMPInfoCache.OMPBuilder.getInsertionPoint().isValid())
1918 OMPInfoCache.OMPBuilder.updateToLocation(
1919 {
F.getEntryBlock().begin(),
DebugLoc()});
1922 uint32_t SrcLocStrSize;
1924 OMPInfoCache.OMPBuilder.getOrCreateDefaultSrcLocStr(SrcLocStrSize);
1925 Ident = OMPInfoCache.OMPBuilder.getOrCreateIdent(Loc, SrcLocStrSize);
1932 bool deduplicateRuntimeCalls(
Function &
F,
1933 OMPInformationCache::RuntimeFunctionInfo &RFI,
1934 Value *ReplVal =
nullptr) {
1935 auto *UV = RFI.getUseVector(
F);
1936 if (!UV || UV->size() + (ReplVal !=
nullptr) < 2)
1940 dbgs() <<
TAG <<
"Deduplicate " << UV->size() <<
" uses of " << RFI.Name
1941 << (ReplVal ?
" with an existing value\n" :
"\n") <<
"\n");
1945 "Unexpected replacement value!");
1948 auto CanBeMoved = [
this](CallBase &CB) {
1954 for (
unsigned U = 1;
U < NumArgs; ++
U)
1962 OMPInfoCache.getAnalysisResultForFunction<DominatorTreeAnalysis>(
F);
1966 for (Use *U : *UV) {
1967 if (CallInst *CI = getCallIfRegularCall(*U, &RFI)) {
1972 if (!CanBeMoved(*CI))
1980 assert(IP &&
"Expected insertion point!");
1990 Value *Ident = getCombinedIdentFromCallUsesIn(RFI,
F,
1998 CallInst *CI = getCallIfRegularCall(U, &RFI);
1999 if (!CI || CI == ReplVal || &
F != &Caller)
2003 auto Remark = [&](OptimizationRemark
OR) {
2004 return OR <<
"OpenMP runtime call "
2005 <<
ore::NV(
"OpenMPOptRuntime", RFI.Name) <<
" deduplicated.";
2014 ++NumOpenMPRuntimeCallsDeduplicated;
2018 RFI.foreachUse(SCC, ReplaceAndDeleteCB);
2024 void collectGlobalThreadIdArguments(SmallSetVector<Value *, 16> >IdArgs) {
2031 auto CallArgOpIsGTId = [&](
Function &
F,
unsigned ArgNo, CallInst &RefCI) {
2032 if (!
F.hasLocalLinkage())
2034 for (Use &U :
F.uses()) {
2035 if (CallInst *CI = getCallIfRegularCall(U)) {
2037 if (CI == &RefCI || GTIdArgs.
count(ArgOp) ||
2038 getCallIfRegularCall(
2039 *ArgOp, &OMPInfoCache.RFIs[OMPRTL___kmpc_global_thread_num]))
2048 auto AddUserArgs = [&](
Value >Id) {
2049 for (Use &U : GTId.uses())
2053 if (CallArgOpIsGTId(*Callee,
U.getOperandNo(), *CI))
2058 OMPInformationCache::RuntimeFunctionInfo &GlobThreadNumRFI =
2059 OMPInfoCache.RFIs[OMPRTL___kmpc_global_thread_num];
2061 GlobThreadNumRFI.foreachUse(SCC, [&](Use &U,
Function &
F) {
2062 if (CallInst *CI = getCallIfRegularCall(U, &GlobThreadNumRFI))
2070 for (
unsigned U = 0;
U < GTIdArgs.
size(); ++
U)
2071 AddUserArgs(*GTIdArgs[U]);
2079 DenseMap<Function *, std::optional<Kernel>> UniqueKernelMap;
2085 Kernel getUniqueKernelFor(Instruction &
I) {
2086 return getUniqueKernelFor(*
I.getFunction());
2091 bool rewriteDeviceCodeStateMachine();
2096 bool removeSPMDParallelWrappers();
2112 template <
typename RemarkKind,
typename RemarkCallBack>
2113 void emitRemark(Instruction *
I, StringRef RemarkName,
2114 RemarkCallBack &&RemarkCB)
const {
2116 auto &ORE = OREGetter(
F);
2120 return RemarkCB(RemarkKind(
DEBUG_TYPE, RemarkName,
I))
2121 <<
" [" << RemarkName <<
"]";
2125 [&]() {
return RemarkCB(RemarkKind(
DEBUG_TYPE, RemarkName,
I)); });
2129 template <
typename RemarkKind,
typename RemarkCallBack>
2131 RemarkCallBack &&RemarkCB)
const {
2132 auto &ORE = OREGetter(
F);
2136 return RemarkCB(RemarkKind(
DEBUG_TYPE, RemarkName,
F))
2137 <<
" [" << RemarkName <<
"]";
2141 [&]() {
return RemarkCB(RemarkKind(
DEBUG_TYPE, RemarkName,
F)); });
2148 SmallVectorImpl<Function *> &SCC;
2152 CallGraphUpdater &CGUpdater;
2155 OptimizationRemarkGetter OREGetter;
2158 OMPInformationCache &OMPInfoCache;
2164 bool runAttributor(
bool IsModulePass) {
2168 registerAAs(IsModulePass);
2173 <<
" functions, result: " <<
Changed <<
".\n");
2175 if (
Changed == ChangeStatus::CHANGED)
2176 OMPInfoCache.invalidateAnalyses();
2178 return Changed == ChangeStatus::CHANGED;
2185 void registerAAs(
bool IsModulePass);
2190 static void registerAAsForFunction(Attributor &A,
const Function &
F);
2194 if (OMPInfoCache.CGSCC && !OMPInfoCache.CGSCC->empty() &&
2195 !OMPInfoCache.CGSCC->contains(&
F))
2200 std::optional<Kernel> &CachedKernel = UniqueKernelMap[&
F];
2202 return *CachedKernel;
2209 return *CachedKernel;
2212 CachedKernel =
nullptr;
2213 if (!
F.hasLocalLinkage()) {
2216 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
2217 return ORA <<
"Potentially unknown OpenMP target region caller.";
2225 auto GetUniqueKernelForUse = [&](
const Use &
U) ->
Kernel {
2228 if (
Cmp->isEquality())
2229 return getUniqueKernelFor(*Cmp);
2235 return getUniqueKernelFor(*CB);
2237 OMPInformationCache::RuntimeFunctionInfo &KernelParallelRFI =
2238 OMPInfoCache.RFIs[OMPRTL___kmpc_parallel_60];
2240 if (OpenMPOpt::getCallIfRegularCall(*
U.getUser(), &KernelParallelRFI))
2241 return getUniqueKernelFor(*CB);
2249 SmallPtrSet<Kernel, 2> PotentialKernels;
2250 OMPInformationCache::foreachUse(
F, [&](
const Use &U) {
2251 PotentialKernels.
insert(GetUniqueKernelForUse(U));
2255 if (PotentialKernels.
size() == 1)
2256 K = *PotentialKernels.
begin();
2259 UniqueKernelMap[&
F] =
K;
2264bool OpenMPOpt::rewriteDeviceCodeStateMachine() {
2265 OMPInformationCache::RuntimeFunctionInfo &KernelParallelRFI =
2266 OMPInfoCache.RFIs[OMPRTL___kmpc_parallel_60];
2269 if (!KernelParallelRFI)
2280 bool UnknownUse =
false;
2281 bool KernelParallelUse =
false;
2282 unsigned NumDirectCalls = 0;
2285 OMPInformationCache::foreachUse(*
F, [&](Use &U) {
2293 ToBeReplacedStateMachineUses.
push_back(&U);
2299 OpenMPOpt::getCallIfRegularCall(*
U.getUser(), &KernelParallelRFI);
2300 const unsigned int WrapperFunctionArgNo = 6;
2301 if (!KernelParallelUse && CI &&
2303 KernelParallelUse =
true;
2304 ToBeReplacedStateMachineUses.
push_back(&U);
2312 if (!KernelParallelUse)
2318 if (UnknownUse || NumDirectCalls != 1 ||
2319 ToBeReplacedStateMachineUses.
size() > 2) {
2320 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
2321 return ORA <<
"Parallel region is used in "
2322 << (UnknownUse ?
"unknown" :
"unexpected")
2323 <<
" ways. Will not attempt to rewrite the state machine.";
2333 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
2334 return ORA <<
"Parallel region is not called from a unique kernel. "
2335 "Will not attempt to rewrite the state machine.";
2347 Type *Int8Ty = Type::getInt8Ty(
M.getContext());
2349 auto *
ID =
new GlobalVariable(
2353 for (Use *U : ToBeReplacedStateMachineUses)
2355 ID,
U->get()->getType()));
2357 ++NumOpenMPParallelRegionsReplacedInGPUStateMachine;
2365bool OpenMPOpt::removeSPMDParallelWrappers() {
2367 if (OMPInfoCache.SPMDizedKernels.empty())
2370 OMPInformationCache::RuntimeFunctionInfo &KernelParallelRFI =
2371 OMPInfoCache.RFIs[OMPRTL___kmpc_parallel_60];
2372 if (!KernelParallelRFI || !KernelParallelRFI.Declaration)
2375 constexpr unsigned WrapperFunctionArgNo = 6;
2377 for (User *U : KernelParallelRFI.Declaration->
users()) {
2380 CI->
arg_size() <= WrapperFunctionArgNo)
2394 if (!K || !OMPInfoCache.SPMDizedKernels.contains(K))
2398 WrapperFunctionArgNo,
2407struct AAICVTracker :
public StateWrapper<BooleanState, AbstractAttribute> {
2408 using Base = StateWrapper<BooleanState, AbstractAttribute>;
2409 AAICVTracker(
const IRPosition &IRP, Attributor &
A) :
Base(IRP) {}
2412 bool isAssumedTracked()
const {
return getAssumed(); }
2415 bool isKnownTracked()
const {
return getAssumed(); }
2418 static AAICVTracker &createForPosition(
const IRPosition &IRP, Attributor &
A);
2422 const Instruction *
I,
2423 Attributor &
A)
const {
2424 return std::nullopt;
2430 virtual std::optional<Value *>
2437 StringRef
getName()
const override {
return "AAICVTracker"; }
2439 const char *getIdAddr()
const override {
return &ID; }
2442 static bool classof(
const AbstractAttribute *AA) {
2446 static const char ID;
2449struct AAICVTrackerFunction :
public AAICVTracker {
2450 AAICVTrackerFunction(
const IRPosition &IRP, Attributor &
A)
2451 : AAICVTracker(IRP,
A) {}
2454 const std::string getAsStr(Attributor *)
const override {
2455 return "ICVTrackerFunction";
2459 void trackStatistics()
const override {}
2463 return ChangeStatus::UNCHANGED;
2468 InternalControlVar::ICV___last>
2469 ICVReplacementValuesMap;
2476 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
2479 auto &SetterRFI = OMPInfoCache.RFIs[OMPInfoCache.ICVs[ICV].Setter];
2481 auto &ValuesMap = ICVReplacementValuesMap[ICV];
2483 CallInst *CI = OpenMPOpt::getCallIfRegularCall(U);
2489 if (ValuesMap.insert(std::make_pair(CI, CI->
getArgOperand(0))).second)
2490 HasChanged = ChangeStatus::CHANGED;
2496 std::optional<Value *> ReplVal = getValueForCall(
A,
I, ICV);
2497 if (ReplVal && ValuesMap.insert(std::make_pair(&
I, *ReplVal)).second)
2498 HasChanged = ChangeStatus::CHANGED;
2504 SetterRFI.foreachUse(TrackValues,
F);
2506 bool UsedAssumedInformation =
false;
2507 A.checkForAllInstructions(CallCheck, *
this, {Instruction::Call},
2508 UsedAssumedInformation,
2514 if (HasChanged == ChangeStatus::CHANGED)
2515 ValuesMap.try_emplace(Entry);
2523 std::optional<Value *> getValueForCall(Attributor &
A,
const Instruction &
I,
2527 if (!CB || CB->
hasFnAttr(
"no_openmp") ||
2530 return std::nullopt;
2532 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
2533 auto &GetterRFI = OMPInfoCache.RFIs[OMPInfoCache.ICVs[ICV].Getter];
2534 auto &SetterRFI = OMPInfoCache.RFIs[OMPInfoCache.ICVs[ICV].Setter];
2538 if (CalledFunction ==
nullptr)
2540 if (CalledFunction == GetterRFI.Declaration)
2541 return std::nullopt;
2542 if (CalledFunction == SetterRFI.Declaration) {
2543 if (ICVReplacementValuesMap[ICV].
count(&
I))
2544 return ICVReplacementValuesMap[ICV].lookup(&
I);
2553 const auto *ICVTrackingAA =
A.getAAFor<AAICVTracker>(
2556 if (ICVTrackingAA->isAssumedTracked()) {
2557 std::optional<Value *> URV =
2558 ICVTrackingAA->getUniqueReplacementValue(ICV);
2569 std::optional<Value *>
2571 return std::nullopt;
2576 const Instruction *
I,
2577 Attributor &
A)
const override {
2578 const auto &ValuesMap = ICVReplacementValuesMap[ICV];
2579 if (ValuesMap.count(
I))
2580 return ValuesMap.lookup(
I);
2583 SmallPtrSet<const Instruction *, 16> Visited;
2586 std::optional<Value *> ReplVal;
2588 while (!Worklist.
empty()) {
2590 if (!Visited.
insert(CurrInst).second)
2598 if (ValuesMap.count(CurrInst)) {
2599 std::optional<Value *> NewReplVal = ValuesMap.lookup(CurrInst);
2602 ReplVal = NewReplVal;
2608 if (ReplVal != NewReplVal)
2614 std::optional<Value *> NewReplVal = getValueForCall(
A, *CurrInst, ICV);
2620 ReplVal = NewReplVal;
2626 if (ReplVal != NewReplVal)
2631 if (CurrBB ==
I->getParent() && ReplVal)
2636 Worklist.
push_back(Pred->getTerminator());
2643struct AAICVTrackerFunctionReturned : AAICVTracker {
2644 AAICVTrackerFunctionReturned(
const IRPosition &IRP, Attributor &
A)
2645 : AAICVTracker(IRP,
A) {}
2648 const std::string getAsStr(Attributor *)
const override {
2649 return "ICVTrackerFunctionReturned";
2653 void trackStatistics()
const override {}
2657 return ChangeStatus::UNCHANGED;
2662 InternalControlVar::ICV___last>
2663 ICVReplacementValuesMap;
2666 std::optional<Value *>
2668 return ICVReplacementValuesMap[ICV];
2673 const auto *ICVTrackingAA =
A.getAAFor<AAICVTracker>(
2676 if (!ICVTrackingAA->isAssumedTracked())
2677 return indicatePessimisticFixpoint();
2680 std::optional<Value *> &ReplVal = ICVReplacementValuesMap[ICV];
2681 std::optional<Value *> UniqueICVValue;
2684 std::optional<Value *> NewReplVal =
2685 ICVTrackingAA->getReplacementValue(ICV, &
I,
A);
2688 if (UniqueICVValue && UniqueICVValue != NewReplVal)
2691 UniqueICVValue = NewReplVal;
2696 bool UsedAssumedInformation =
false;
2697 if (!
A.checkForAllInstructions(CheckReturnInst, *
this, {Instruction::Ret},
2698 UsedAssumedInformation,
2700 UniqueICVValue =
nullptr;
2702 if (UniqueICVValue == ReplVal)
2705 ReplVal = UniqueICVValue;
2706 Changed = ChangeStatus::CHANGED;
2713struct AAICVTrackerCallSite : AAICVTracker {
2714 AAICVTrackerCallSite(
const IRPosition &IRP, Attributor &
A)
2715 : AAICVTracker(IRP,
A) {}
2718 assert(getAnchorScope() &&
"Expected anchor function");
2722 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
2724 auto ICVInfo = OMPInfoCache.ICVs[ICV];
2725 auto &Getter = OMPInfoCache.RFIs[ICVInfo.Getter];
2726 if (Getter.Declaration == getAssociatedFunction()) {
2727 AssociatedICV = ICVInfo.Kind;
2733 indicatePessimisticFixpoint();
2737 if (!ReplVal || !*ReplVal)
2738 return ChangeStatus::UNCHANGED;
2741 A.deleteAfterManifest(*getCtxI());
2743 return ChangeStatus::CHANGED;
2747 const std::string getAsStr(Attributor *)
const override {
2748 return "ICVTrackerCallSite";
2752 void trackStatistics()
const override {}
2755 std::optional<Value *> ReplVal;
2758 const auto *ICVTrackingAA =
A.getAAFor<AAICVTracker>(
2762 if (!ICVTrackingAA->isAssumedTracked())
2763 return indicatePessimisticFixpoint();
2765 std::optional<Value *> NewReplVal =
2766 ICVTrackingAA->getReplacementValue(AssociatedICV, getCtxI(),
A);
2768 if (ReplVal == NewReplVal)
2769 return ChangeStatus::UNCHANGED;
2771 ReplVal = NewReplVal;
2772 return ChangeStatus::CHANGED;
2777 std::optional<Value *>
2783struct AAICVTrackerCallSiteReturned : AAICVTracker {
2784 AAICVTrackerCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
2785 : AAICVTracker(IRP,
A) {}
2788 const std::string getAsStr(Attributor *)
const override {
2789 return "ICVTrackerCallSiteReturned";
2793 void trackStatistics()
const override {}
2797 return ChangeStatus::UNCHANGED;
2802 InternalControlVar::ICV___last>
2803 ICVReplacementValuesMap;
2807 std::optional<Value *>
2809 return ICVReplacementValuesMap[ICV];
2814 const auto *ICVTrackingAA =
A.getAAFor<AAICVTracker>(
2816 DepClassTy::REQUIRED);
2819 if (!ICVTrackingAA->isAssumedTracked())
2820 return indicatePessimisticFixpoint();
2823 std::optional<Value *> &ReplVal = ICVReplacementValuesMap[ICV];
2824 std::optional<Value *> NewReplVal =
2825 ICVTrackingAA->getUniqueReplacementValue(ICV);
2827 if (ReplVal == NewReplVal)
2830 ReplVal = NewReplVal;
2831 Changed = ChangeStatus::CHANGED;
2839static bool hasFunctionEndAsUniqueSuccessor(
const BasicBlock *BB) {
2845 return hasFunctionEndAsUniqueSuccessor(
Successor);
2848struct AAExecutionDomainFunction :
public AAExecutionDomain {
2849 AAExecutionDomainFunction(
const IRPosition &IRP, Attributor &
A)
2850 : AAExecutionDomain(IRP,
A) {}
2852 ~AAExecutionDomainFunction()
override {
delete RPOT; }
2856 assert(
F &&
"Expected anchor function");
2857 RPOT =
new ReversePostOrderTraversal<Function *>(
F);
2860 const std::string getAsStr(Attributor *)
const override {
2861 unsigned TotalBlocks = 0, InitialThreadBlocks = 0, AlignedBlocks = 0;
2862 for (
auto &It : BEDMap) {
2866 InitialThreadBlocks += It.getSecond().IsExecutedByInitialThreadOnly;
2867 AlignedBlocks += It.getSecond().IsReachedFromAlignedBarrierOnly &&
2868 It.getSecond().IsReachingAlignedBarrierOnly;
2870 return "[AAExecutionDomain] " + std::to_string(InitialThreadBlocks) +
"/" +
2871 std::to_string(AlignedBlocks) +
" of " +
2872 std::to_string(TotalBlocks) +
2873 " executed by initial thread / aligned";
2876 void trackStatistics()
const override {}
2880 for (
const BasicBlock &BB : *getAnchorScope()) {
2881 if (!isExecutedByInitialThreadOnly(BB))
2883 dbgs() <<
TAG <<
" Basic block @" << getAnchorScope()->getName() <<
" "
2884 << BB.
getName() <<
" is executed by a single thread.\n";
2893 SmallPtrSet<CallBase *, 16> DeletedBarriers;
2894 auto HandleAlignedBarrier = [&](CallBase *CB) {
2895 const ExecutionDomainTy &ED = CB ? CEDMap[{CB, PRE}] : BEDMap[
nullptr];
2896 if (!ED.IsReachedFromAlignedBarrierOnly ||
2897 ED.EncounteredNonLocalSideEffect)
2899 if (!ED.EncounteredAssumes.empty() && !
A.isModulePass())
2910 DeletedBarriers.
insert(CB);
2911 A.deleteAfterManifest(*CB);
2912 ++NumBarriersEliminated;
2913 Changed = ChangeStatus::CHANGED;
2914 }
else if (!ED.AlignedBarriers.empty()) {
2915 Changed = ChangeStatus::CHANGED;
2917 ED.AlignedBarriers.end());
2918 SmallSetVector<CallBase *, 16> Visited;
2919 while (!Worklist.
empty()) {
2921 if (!Visited.
insert(LastCB))
2925 if (!hasFunctionEndAsUniqueSuccessor(LastCB->
getParent()))
2927 if (!DeletedBarriers.
count(LastCB)) {
2928 ++NumBarriersEliminated;
2929 A.deleteAfterManifest(*LastCB);
2935 const ExecutionDomainTy &LastED = CEDMap[{LastCB, PRE}];
2936 Worklist.
append(LastED.AlignedBarriers.begin(),
2937 LastED.AlignedBarriers.end());
2943 if (!ED.EncounteredAssumes.empty() && (CB || !ED.AlignedBarriers.empty()))
2944 for (
auto *AssumeCB : ED.EncounteredAssumes)
2945 A.deleteAfterManifest(*AssumeCB);
2948 for (
auto *CB : AlignedBarriers)
2949 HandleAlignedBarrier(CB);
2953 HandleAlignedBarrier(
nullptr);
2958 bool isNoOpFence(
const FenceInst &FI)
const override {
2959 return getState().isValidState() && !NonNoOpFences.count(&FI);
2965 mergeInPredecessorBarriersAndAssumptions(Attributor &
A, ExecutionDomainTy &ED,
2966 const ExecutionDomainTy &PredED);
2971 bool mergeInPredecessor(Attributor &
A, ExecutionDomainTy &ED,
2972 const ExecutionDomainTy &PredED,
2973 bool InitialEdgeOnly =
false);
2976 bool handleCallees(Attributor &
A, ExecutionDomainTy &EntryBBED);
2982 bool isExecutedByInitialThreadOnly(
const BasicBlock &BB)
const override {
2983 if (!isValidState())
2985 assert(BB.
getParent() == getAnchorScope() &&
"Block is out of scope!");
2986 return BEDMap.lookup(&BB).IsExecutedByInitialThreadOnly;
2989 bool isExecutedInAlignedRegion(Attributor &
A,
2990 const Instruction &
I)
const override {
2991 assert(
I.getFunction() == getAnchorScope() &&
2992 "Instruction is out of scope!");
2993 if (!isValidState())
2996 bool ForwardIsOk =
true;
3005 if (CB != &
I && AlignedBarriers.contains(
const_cast<CallBase *
>(CB)))
3007 const auto &It = CEDMap.find({CB, PRE});
3008 if (It == CEDMap.end())
3010 if (!It->getSecond().IsReachingAlignedBarrierOnly)
3011 ForwardIsOk =
false;
3015 if (!CurI && !BEDMap.lookup(
I.getParent()).IsReachingAlignedBarrierOnly)
3016 ForwardIsOk =
false;
3024 if (CB != &
I && AlignedBarriers.contains(
const_cast<CallBase *
>(CB)))
3026 const auto &It = CEDMap.find({CB, POST});
3027 if (It == CEDMap.end())
3029 if (It->getSecond().IsReachedFromAlignedBarrierOnly)
3042 return BEDMap.lookup(
nullptr).IsReachedFromAlignedBarrierOnly;
3044 return BEDMap.lookup(PredBB).IsReachedFromAlignedBarrierOnly;
3054 ExecutionDomainTy getExecutionDomain(
const BasicBlock &BB)
const override {
3056 "No request should be made against an invalid state!");
3057 return BEDMap.lookup(&BB);
3059 std::pair<ExecutionDomainTy, ExecutionDomainTy>
3060 getExecutionDomain(
const CallBase &CB)
const override {
3062 "No request should be made against an invalid state!");
3063 return {CEDMap.lookup({&CB, PRE}), CEDMap.lookup({&CB, POST})};
3065 ExecutionDomainTy getFunctionExecutionDomain()
const override {
3067 "No request should be made against an invalid state!");
3068 return InterProceduralED;
3074 static bool isInitialThreadOnlyEdge(Attributor &
A, CondBrInst *
Edge,
3075 BasicBlock &SuccessorBB) {
3078 if (
Edge->getSuccessor(0) != &SuccessorBB)
3082 if (!Cmp || !
Cmp->isTrueWhenEqual() || !
Cmp->isEquality())
3090 if (
C->isAllOnesValue()) {
3092 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
3093 auto &RFI = OMPInfoCache.RFIs[OMPRTL___kmpc_target_init];
3094 CB = CB ? OpenMPOpt::getCallIfRegularCall(*CB, &RFI) : nullptr;
3097 ConstantStruct *KernelEnvC =
3099 ConstantInt *ExecModeC =
3100 KernelInfo::getExecModeFromKernelEnvironment(KernelEnvC);
3107 if (
II->getIntrinsicID() == Intrinsic::nvvm_read_ptx_sreg_tid_x)
3112 if (
II->getIntrinsicID() == Intrinsic::amdgcn_workitem_id_x)
3120 ExecutionDomainTy InterProceduralED;
3124 DenseMap<const BasicBlock *, ExecutionDomainTy> BEDMap;
3125 DenseMap<PointerIntPair<const CallBase *, 1, Direction>, ExecutionDomainTy>
3127 SmallSetVector<CallBase *, 16> AlignedBarriers;
3129 ReversePostOrderTraversal<Function *> *RPOT =
nullptr;
3132 static bool setAndRecord(
bool &R,
bool V) {
3140 SmallPtrSet<const FenceInst *, 8> NonNoOpFences;
3143void AAExecutionDomainFunction::mergeInPredecessorBarriersAndAssumptions(
3144 Attributor &
A, ExecutionDomainTy &ED,
const ExecutionDomainTy &PredED) {
3145 for (
auto *EA : PredED.EncounteredAssumes)
3146 ED.addAssumeInst(
A, *EA);
3148 for (
auto *AB : PredED.AlignedBarriers)
3149 ED.addAlignedBarrier(
A, *AB);
3152bool AAExecutionDomainFunction::mergeInPredecessor(
3153 Attributor &
A, ExecutionDomainTy &ED,
const ExecutionDomainTy &PredED,
3154 bool InitialEdgeOnly) {
3158 setAndRecord(ED.IsExecutedByInitialThreadOnly,
3159 InitialEdgeOnly || (PredED.IsExecutedByInitialThreadOnly &&
3160 ED.IsExecutedByInitialThreadOnly));
3162 Changed |= setAndRecord(ED.IsReachedFromAlignedBarrierOnly,
3163 ED.IsReachedFromAlignedBarrierOnly &&
3164 PredED.IsReachedFromAlignedBarrierOnly);
3165 Changed |= setAndRecord(ED.EncounteredNonLocalSideEffect,
3166 ED.EncounteredNonLocalSideEffect |
3167 PredED.EncounteredNonLocalSideEffect);
3169 if (ED.IsReachedFromAlignedBarrierOnly)
3170 mergeInPredecessorBarriersAndAssumptions(
A, ED, PredED);
3172 ED.clearAssumeInstAndAlignedBarriers();
3176bool AAExecutionDomainFunction::handleCallees(Attributor &
A,
3177 ExecutionDomainTy &EntryBBED) {
3179 auto PredForCallSite = [&](AbstractCallSite ACS) {
3180 const auto *EDAA =
A.getAAFor<AAExecutionDomain>(
3182 DepClassTy::OPTIONAL);
3183 if (!EDAA || !EDAA->getState().isValidState())
3186 EDAA->getExecutionDomain(*
cast<CallBase>(ACS.getInstruction())));
3190 ExecutionDomainTy ExitED;
3191 bool AllCallSitesKnown;
3192 if (
A.checkForAllCallSites(PredForCallSite, *
this,
3194 AllCallSitesKnown)) {
3195 for (
const auto &[CSInED, CSOutED] : CallSiteEDs) {
3196 mergeInPredecessor(
A, EntryBBED, CSInED);
3197 ExitED.IsReachingAlignedBarrierOnly &=
3198 CSOutED.IsReachingAlignedBarrierOnly;
3205 EntryBBED.IsExecutedByInitialThreadOnly =
false;
3206 EntryBBED.IsReachedFromAlignedBarrierOnly =
true;
3207 EntryBBED.EncounteredNonLocalSideEffect =
false;
3208 ExitED.IsReachingAlignedBarrierOnly =
false;
3210 EntryBBED.IsExecutedByInitialThreadOnly =
false;
3211 EntryBBED.IsReachedFromAlignedBarrierOnly =
false;
3212 EntryBBED.EncounteredNonLocalSideEffect =
true;
3213 ExitED.IsReachingAlignedBarrierOnly =
false;
3218 auto &FnED = BEDMap[
nullptr];
3219 Changed |= setAndRecord(FnED.IsReachedFromAlignedBarrierOnly,
3220 FnED.IsReachedFromAlignedBarrierOnly &
3221 EntryBBED.IsReachedFromAlignedBarrierOnly);
3222 Changed |= setAndRecord(FnED.IsReachingAlignedBarrierOnly,
3223 FnED.IsReachingAlignedBarrierOnly &
3224 ExitED.IsReachingAlignedBarrierOnly);
3225 Changed |= setAndRecord(FnED.IsExecutedByInitialThreadOnly,
3226 EntryBBED.IsExecutedByInitialThreadOnly);
3230ChangeStatus AAExecutionDomainFunction::updateImpl(Attributor &
A) {
3237 auto HandleAlignedBarrier = [&](CallBase &CB, ExecutionDomainTy &ED) {
3238 Changed |= AlignedBarriers.insert(&CB);
3240 auto &CallInED = CEDMap[{&CB, PRE}];
3241 Changed |= mergeInPredecessor(
A, CallInED, ED);
3242 CallInED.IsReachingAlignedBarrierOnly =
true;
3244 ED.EncounteredNonLocalSideEffect =
false;
3245 ED.IsReachedFromAlignedBarrierOnly =
true;
3247 ED.clearAssumeInstAndAlignedBarriers();
3248 ED.addAlignedBarrier(
A, CB);
3249 auto &CallOutED = CEDMap[{&CB, POST}];
3250 Changed |= mergeInPredecessor(
A, CallOutED, ED);
3254 A.getAAFor<AAIsDead>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
3260 SmallVector<Instruction *> SyncInstWorklist;
3261 for (
auto &RIt : *RPOT) {
3264 bool IsEntryBB = &BB == &EntryBB;
3267 bool AlignedBarrierLastInBlock = IsEntryBB && IsKernel;
3268 bool IsExplicitlyAligned = IsEntryBB && IsKernel;
3269 ExecutionDomainTy ED;
3276 if (LivenessAA && LivenessAA->isAssumedDead(&BB))
3280 if (LivenessAA && LivenessAA->isEdgeDead(PredBB, &BB))
3282 bool InitialEdgeOnly = isInitialThreadOnlyEdge(
3284 mergeInPredecessor(
A, ED, BEDMap[PredBB], InitialEdgeOnly);
3290 for (Instruction &
I : BB) {
3291 bool UsedAssumedInformation;
3292 if (
A.isAssumedDead(
I, *
this, LivenessAA, UsedAssumedInformation,
3293 false, DepClassTy::OPTIONAL,
3301 ED.addAssumeInst(
A, *AI);
3305 if (
II->isAssumeLikeIntrinsic())
3310 if (!ED.EncounteredNonLocalSideEffect) {
3312 if (ED.IsReachedFromAlignedBarrierOnly)
3317 case AtomicOrdering::NotAtomic:
3319 case AtomicOrdering::Unordered:
3321 case AtomicOrdering::Monotonic:
3323 case AtomicOrdering::Acquire:
3325 case AtomicOrdering::Release:
3327 case AtomicOrdering::AcquireRelease:
3329 case AtomicOrdering::SequentiallyConsistent:
3333 NonNoOpFences.insert(FI);
3338 bool IsAlignedBarrier =
3342 AlignedBarrierLastInBlock &= IsNoSync;
3343 IsExplicitlyAligned &= IsNoSync;
3349 if (IsAlignedBarrier) {
3350 HandleAlignedBarrier(*CB, ED);
3351 AlignedBarrierLastInBlock =
true;
3352 IsExplicitlyAligned =
true;
3358 if (!ED.EncounteredNonLocalSideEffect &&
3360 ED.EncounteredNonLocalSideEffect =
true;
3362 ED.IsReachedFromAlignedBarrierOnly =
false;
3370 auto &CallInED = CEDMap[{CB, PRE}];
3371 Changed |= mergeInPredecessor(
A, CallInED, ED);
3377 if (!IsNoSync && Callee && !
Callee->isDeclaration()) {
3378 const auto *EDAA =
A.getAAFor<AAExecutionDomain>(
3380 if (EDAA && EDAA->getState().isValidState()) {
3381 const auto &CalleeED = EDAA->getFunctionExecutionDomain();
3382 ED.IsReachedFromAlignedBarrierOnly =
3383 CalleeED.IsReachedFromAlignedBarrierOnly;
3384 AlignedBarrierLastInBlock = ED.IsReachedFromAlignedBarrierOnly;
3385 if (IsNoSync || !CalleeED.IsReachedFromAlignedBarrierOnly)
3386 ED.EncounteredNonLocalSideEffect |=
3387 CalleeED.EncounteredNonLocalSideEffect;
3389 ED.EncounteredNonLocalSideEffect =
3390 CalleeED.EncounteredNonLocalSideEffect;
3391 if (!CalleeED.IsReachingAlignedBarrierOnly) {
3393 setAndRecord(CallInED.IsReachingAlignedBarrierOnly,
false);
3396 if (CalleeED.IsReachedFromAlignedBarrierOnly)
3397 mergeInPredecessorBarriersAndAssumptions(
A, ED, CalleeED);
3398 auto &CallOutED = CEDMap[{CB, POST}];
3399 Changed |= mergeInPredecessor(
A, CallOutED, ED);
3404 ED.IsReachedFromAlignedBarrierOnly =
false;
3405 Changed |= setAndRecord(CallInED.IsReachingAlignedBarrierOnly,
false);
3408 AlignedBarrierLastInBlock &= ED.IsReachedFromAlignedBarrierOnly;
3410 auto &CallOutED = CEDMap[{CB, POST}];
3411 Changed |= mergeInPredecessor(
A, CallOutED, ED);
3414 if (!
I.mayHaveSideEffects() && !
I.mayReadFromMemory())
3420 const auto *MemAA =
A.getAAFor<AAMemoryLocation>(
3428 if (MemAA && MemAA->getState().isValidState() &&
3429 MemAA->checkForAllAccessesToMemoryKind(
3434 auto &InfoCache =
A.getInfoCache();
3435 if (!
I.mayHaveSideEffects() && InfoCache.isOnlyUsedByAssume(
I))
3439 if (LI->hasMetadata(LLVMContext::MD_invariant_load))
3442 if (!ED.EncounteredNonLocalSideEffect &&
3444 ED.EncounteredNonLocalSideEffect =
true;
3447 bool IsEndAndNotReachingAlignedBarriersOnly =
false;
3449 !BB.getTerminator()->getNumSuccessors()) {
3451 Changed |= mergeInPredecessor(
A, InterProceduralED, ED);
3453 auto &FnED = BEDMap[
nullptr];
3454 if (IsKernel && !IsExplicitlyAligned)
3455 FnED.IsReachingAlignedBarrierOnly =
false;
3456 Changed |= mergeInPredecessor(
A, FnED, ED);
3458 if (!FnED.IsReachingAlignedBarrierOnly) {
3459 IsEndAndNotReachingAlignedBarriersOnly =
true;
3460 SyncInstWorklist.
push_back(BB.getTerminator());
3461 auto &BBED = BEDMap[&BB];
3462 Changed |= setAndRecord(BBED.IsReachingAlignedBarrierOnly,
false);
3466 ExecutionDomainTy &StoredED = BEDMap[&BB];
3467 ED.IsReachingAlignedBarrierOnly = StoredED.IsReachingAlignedBarrierOnly &&
3468 !IsEndAndNotReachingAlignedBarriersOnly;
3474 if (ED.IsExecutedByInitialThreadOnly !=
3475 StoredED.IsExecutedByInitialThreadOnly ||
3476 ED.IsReachedFromAlignedBarrierOnly !=
3477 StoredED.IsReachedFromAlignedBarrierOnly ||
3478 ED.EncounteredNonLocalSideEffect !=
3479 StoredED.EncounteredNonLocalSideEffect)
3483 StoredED = std::move(ED);
3488 SmallSetVector<BasicBlock *, 16> Visited;
3489 while (!SyncInstWorklist.
empty()) {
3492 bool HitAlignedBarrierOrKnownEnd =
false;
3497 auto &CallOutED = CEDMap[{CB, POST}];
3498 Changed |= setAndRecord(CallOutED.IsReachingAlignedBarrierOnly,
false);
3499 auto &CallInED = CEDMap[{CB, PRE}];
3500 HitAlignedBarrierOrKnownEnd =
3501 AlignedBarriers.count(CB) || !CallInED.IsReachingAlignedBarrierOnly;
3502 if (HitAlignedBarrierOrKnownEnd)
3504 Changed |= setAndRecord(CallInED.IsReachingAlignedBarrierOnly,
false);
3506 if (HitAlignedBarrierOrKnownEnd)
3510 if (LivenessAA && LivenessAA->isEdgeDead(PredBB, SyncBB))
3512 if (!Visited.
insert(PredBB))
3514 auto &PredED = BEDMap[PredBB];
3515 if (setAndRecord(PredED.IsReachingAlignedBarrierOnly,
false)) {
3517 SyncInstWorklist.
push_back(PredBB->getTerminator());
3520 if (SyncBB != &EntryBB)
3523 setAndRecord(InterProceduralED.IsReachingAlignedBarrierOnly,
false);
3526 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
3531struct AAHeapToShared :
public StateWrapper<BooleanState, AbstractAttribute> {
3532 using Base = StateWrapper<BooleanState, AbstractAttribute>;
3533 AAHeapToShared(
const IRPosition &IRP, Attributor &
A) :
Base(IRP) {}
3536 static AAHeapToShared &createForPosition(
const IRPosition &IRP,
3540 virtual bool isAssumedHeapToShared(CallBase &CB)
const = 0;
3544 virtual bool isAssumedHeapToSharedRemovedFree(CallBase &CB)
const = 0;
3546 StringRef
getName()
const override {
return "AAHeapToShared"; }
3548 const char *getIdAddr()
const override {
return &ID; }
3552 static bool classof(
const AbstractAttribute *AA) {
3557 static const char ID;
3560struct AAHeapToSharedFunction :
public AAHeapToShared {
3561 AAHeapToSharedFunction(
const IRPosition &IRP, Attributor &
A)
3562 : AAHeapToShared(IRP,
A) {}
3564 const std::string getAsStr(Attributor *)
const override {
3565 return "[AAHeapToShared] " + std::to_string(MallocCalls.size()) +
3566 " malloc calls eligible.";
3569 void trackStatistics()
const override {}
3573 void findPotentialRemovedFreeCalls(Attributor &
A) {
3574 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
3575 auto &FreeRFI = OMPInfoCache.RFIs[OMPRTL___kmpc_free_shared];
3577 PotentialRemovedFreeCalls.clear();
3579 for (CallBase *CB : MallocCalls) {
3581 for (
auto *U : CB->
users()) {
3583 if (
C &&
C->getCalledFunction() == FreeRFI.Declaration)
3587 if (FreeCalls.
size() != 1)
3590 PotentialRemovedFreeCalls.insert(FreeCalls.
front());
3596 indicatePessimisticFixpoint();
3600 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
3601 auto &RFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
3602 if (!RFI.Declaration)
3606 [](
const IRPosition &,
const AbstractAttribute *,
3607 bool &) -> std::optional<Value *> {
return nullptr; };
3610 const OMPInformationCache::RuntimeFunctionInfo::UseVector *
Uses =
3611 RFI.getUseVector(*
F);
3615 for (Use *U : *
Uses)
3617 MallocCalls.insert(CB);
3622 findPotentialRemovedFreeCalls(
A);
3625 bool isAssumedHeapToShared(CallBase &CB)
const override {
3626 return isValidState() && MallocCalls.count(&CB);
3629 bool isAssumedHeapToSharedRemovedFree(CallBase &CB)
const override {
3630 return isValidState() && PotentialRemovedFreeCalls.count(&CB);
3634 if (MallocCalls.empty())
3635 return ChangeStatus::UNCHANGED;
3637 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
3638 auto &FreeCall = OMPInfoCache.RFIs[OMPRTL___kmpc_free_shared];
3642 DepClassTy::OPTIONAL);
3645 for (CallBase *CB : MallocCalls) {
3647 if (HS &&
HS->isAssumedHeapToStack(*CB))
3652 for (
auto *U : CB->
users()) {
3654 if (
C &&
C->getCalledFunction() == FreeCall.Declaration)
3657 if (FreeCalls.
size() != 1)
3664 <<
" with shared memory."
3665 <<
" Shared memory usage is limited to "
3671 <<
" with " << AllocSize->getZExtValue()
3672 <<
" bytes of shared memory\n");
3677 Type *Int8Ty = Type::getInt8Ty(
M->getContext());
3678 Type *Int8ArrTy = ArrayType::get(Int8Ty, AllocSize->getZExtValue());
3679 auto *SharedMem =
new GlobalVariable(
3683 static_cast<unsigned>(AddressSpace::Shared));
3685 SharedMem, PointerType::getUnqual(
M->getContext()));
3687 auto Remark = [&](OptimizationRemark
OR) {
3688 return OR <<
"Replaced globalized variable with "
3689 <<
ore::NV(
"SharedMemory", AllocSize->getZExtValue())
3690 << (AllocSize->isOne() ?
" byte " :
" bytes ")
3691 <<
"of shared memory.";
3693 A.emitRemark<OptimizationRemark>(CB,
"OMP111",
Remark);
3695 MaybeAlign
Alignment = CB->getRetAlign();
3697 "HeapToShared on allocation without alignment attribute");
3701 A.deleteAfterManifest(*CB);
3702 A.deleteAfterManifest(*FreeCalls.
front());
3704 SharedMemoryUsed += AllocSize->getZExtValue();
3705 NumBytesMovedToSharedMemory = SharedMemoryUsed;
3706 Changed = ChangeStatus::CHANGED;
3713 if (MallocCalls.empty())
3714 return indicatePessimisticFixpoint();
3715 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
3716 auto &RFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
3717 if (!RFI.Declaration)
3718 return ChangeStatus::UNCHANGED;
3722 auto NumMallocCalls = MallocCalls.size();
3725 for (User *U : RFI.Declaration->
users()) {
3727 if (CB->getCaller() !=
F)
3729 if (!MallocCalls.count(CB))
3732 MallocCalls.remove(CB);
3735 const auto *ED =
A.getAAFor<AAExecutionDomain>(
3737 if (!ED || !ED->isExecutedByInitialThreadOnly(*CB))
3738 MallocCalls.remove(CB);
3742 findPotentialRemovedFreeCalls(
A);
3744 if (NumMallocCalls != MallocCalls.size())
3745 return ChangeStatus::CHANGED;
3747 return ChangeStatus::UNCHANGED;
3751 SmallSetVector<CallBase *, 4> MallocCalls;
3753 SmallPtrSet<CallBase *, 4> PotentialRemovedFreeCalls;
3755 unsigned SharedMemoryUsed = 0;
3758struct AAKernelInfo :
public StateWrapper<KernelInfoState, AbstractAttribute> {
3759 using Base = StateWrapper<KernelInfoState, AbstractAttribute>;
3760 AAKernelInfo(
const IRPosition &IRP, Attributor &
A) :
Base(IRP) {}
3764 static bool requiresCalleeForCallBase() {
return false; }
3767 void trackStatistics()
const override {}
3769 const std::string getAsStr(Attributor *)
const override {
3770 if (!isValidState())
3772 return std::string(SPMDCompatibilityTracker.isAssumed() ?
"SPMD"
3774 std::string(SPMDCompatibilityTracker.isAtFixpoint() ?
" [FIX]"
3776 std::string(
" #PRs: ") +
3777 (ReachedKnownParallelRegions.isValidState()
3778 ? std::to_string(ReachedKnownParallelRegions.size())
3780 ", #Unknown PRs: " +
3781 (ReachedUnknownParallelRegions.isValidState()
3782 ? std::to_string(ReachedUnknownParallelRegions.size())
3784 ", #Reaching Kernels: " +
3785 (ReachingKernelEntries.isValidState()
3786 ? std::to_string(ReachingKernelEntries.size())
3789 (ParallelLevels.isValidState()
3790 ? std::to_string(ParallelLevels.size())
3792 ", NestedPar: " + (NestedParallelism ?
"yes" :
"no");
3796 static AAKernelInfo &createForPosition(
const IRPosition &IRP, Attributor &
A);
3798 StringRef
getName()
const override {
return "AAKernelInfo"; }
3800 const char *getIdAddr()
const override {
return &ID; }
3803 static bool classof(
const AbstractAttribute *AA) {
3807 static const char ID;
3811static bool isStrictFence(
const Instruction &
I) {
3827 switch (Parsed->first) {
3828 case AtomicScope::Single:
3829 case AtomicScope::Wavefront:
3830 case AtomicScope::Workgroup:
3832 case AtomicScope::Cluster:
3833 case AtomicScope::Device:
3834 case AtomicScope::System:
3842struct AAKernelInfoFunction : AAKernelInfo {
3843 AAKernelInfoFunction(
const IRPosition &IRP, Attributor &
A)
3844 : AAKernelInfo(IRP,
A) {}
3846 SmallPtrSet<Instruction *, 4> GuardedInstructions;
3848 SmallPtrSetImpl<Instruction *> &getGuardedInstructions() {
3849 return GuardedInstructions;
3852 void setConfigurationOfKernelEnvironment(ConstantStruct *ConfigC) {
3854 KernelEnvC, ConfigC, {KernelInfo::ConfigurationIdx});
3855 assert(NewKernelEnvC &&
"Failed to create new kernel environment");
3859#define KERNEL_ENVIRONMENT_CONFIGURATION_SETTER(MEMBER) \
3860 void set##MEMBER##OfKernelEnvironment(ConstantInt *NewVal) { \
3861 ConstantStruct *ConfigC = \
3862 KernelInfo::getConfigurationFromKernelEnvironment(KernelEnvC); \
3863 Constant *NewConfigC = ConstantFoldInsertValueInstruction( \
3864 ConfigC, NewVal, {KernelInfo::MEMBER##Idx}); \
3865 assert(NewConfigC && "Failed to create new configuration environment"); \
3866 setConfigurationOfKernelEnvironment(cast<ConstantStruct>(NewConfigC)); \
3877#undef KERNEL_ENVIRONMENT_CONFIGURATION_SETTER
3883 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
3887 OMPInformationCache::RuntimeFunctionInfo &InitRFI =
3888 OMPInfoCache.RFIs[OMPRTL___kmpc_target_init];
3889 OMPInformationCache::RuntimeFunctionInfo &DeinitRFI =
3890 OMPInfoCache.RFIs[OMPRTL___kmpc_target_deinit];
3894 auto StoreCallBase = [](
Use &U,
3895 OMPInformationCache::RuntimeFunctionInfo &RFI,
3897 CallBase *CB = OpenMPOpt::getCallIfRegularCall(U, &RFI);
3899 "Unexpected use of __kmpc_target_init or __kmpc_target_deinit!");
3901 "Multiple uses of __kmpc_target_init or __kmpc_target_deinit!");
3907 StoreCallBase(U, InitRFI, KernelInitCB);
3911 DeinitRFI.foreachUse(
3913 StoreCallBase(U, DeinitRFI, KernelDeinitCB);
3919 if (!KernelInitCB || !KernelDeinitCB)
3923 ReachingKernelEntries.insert(Fn);
3924 IsKernelEntry =
true;
3932 KernelConfigurationSimplifyCB =
3934 bool &UsedAssumedInformation) -> std::optional<Constant *> {
3935 if (!isAtFixpoint()) {
3938 UsedAssumedInformation =
true;
3944 A.registerGlobalVariableSimplificationCallback(
3945 *KernelEnvGV, KernelConfigurationSimplifyCB);
3948 bool CanChangeToSPMD = OMPInfoCache.runtimeFnsAvailable(
3949 {OMPRTL___kmpc_get_hardware_thread_id_in_block,
3950 OMPRTL___kmpc_barrier_simple_spmd});
3954 KernelInfo::getExecModeFromKernelEnvironment(KernelEnvC);
3959 SPMDCompatibilityTracker.indicateOptimisticFixpoint();
3963 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
3965 setExecModeOfKernelEnvironment(AssumedExecModeC);
3969 auto [MinThreads, MaxThreads] =
3972 setMinThreadsOfKernelEnvironment(ConstantInt::get(Int32Ty, MinThreads));
3974 setMaxThreadsOfKernelEnvironment(ConstantInt::get(Int32Ty, MaxThreads));
3975 auto [MinTeams, MaxTeams] =
3978 setMinTeamsOfKernelEnvironment(ConstantInt::get(Int32Ty, MinTeams));
3980 setMaxTeamsOfKernelEnvironment(ConstantInt::get(Int32Ty, MaxTeams));
3983 KernelInfo::getMayUseNestedParallelismFromKernelEnvironment(KernelEnvC);
3984 ConstantInt *AssumedMayUseNestedParallelismC = ConstantInt::get(
3986 setMayUseNestedParallelismOfKernelEnvironment(
3987 AssumedMayUseNestedParallelismC);
3991 KernelInfo::getUseGenericStateMachineFromKernelEnvironment(
3994 ConstantInt::get(UseGenericStateMachineC->
getIntegerType(),
false);
3995 setUseGenericStateMachineOfKernelEnvironment(
3996 AssumedUseGenericStateMachineC);
4002 if (!OMPInfoCache.RFIs[RFKind].Declaration)
4004 A.registerVirtualUseCallback(*OMPInfoCache.RFIs[RFKind].Declaration, CB);
4008 auto AddDependence = [](
Attributor &
A,
const AAKernelInfo *KI,
4024 if (SPMDCompatibilityTracker.isValidState())
4025 return AddDependence(
A,
this, QueryingAA);
4027 if (!ReachedKnownParallelRegions.isValidState())
4028 return AddDependence(
A,
this, QueryingAA);
4034 RegisterVirtualUse(OMPRTL___kmpc_get_max_team_threads,
4035 CustomStateMachineUseCB);
4036 RegisterVirtualUse(OMPRTL___kmpc_barrier_simple_generic,
4037 CustomStateMachineUseCB);
4038 RegisterVirtualUse(OMPRTL___kmpc_kernel_parallel,
4039 CustomStateMachineUseCB);
4040 RegisterVirtualUse(OMPRTL___kmpc_kernel_end_parallel,
4041 CustomStateMachineUseCB);
4045 if (SPMDCompatibilityTracker.isAtFixpoint())
4052 if (!SPMDCompatibilityTracker.isValidState())
4053 return AddDependence(
A,
this, QueryingAA);
4056 RegisterVirtualUse(OMPRTL___kmpc_get_hardware_thread_id_in_block,
4065 if (!SPMDCompatibilityTracker.isValidState())
4066 return AddDependence(
A,
this, QueryingAA);
4067 if (SPMDCompatibilityTracker.empty())
4068 return AddDependence(
A,
this, QueryingAA);
4069 if (!mayContainParallelRegion())
4070 return AddDependence(
A,
this, QueryingAA);
4073 RegisterVirtualUse(OMPRTL___kmpc_barrier_simple_spmd, SPMDBarrierUseCB);
4077 static std::string sanitizeForGlobalName(std::string S) {
4081 return !((C >=
'a' && C <=
'z') || (C >=
'A' && C <=
'Z') ||
4082 (C >=
'0' && C <=
'9') || C ==
'_');
4093 if (!KernelInitCB || !KernelDeinitCB)
4094 return ChangeStatus::UNCHANGED;
4098 bool HasBuiltStateMachine =
true;
4099 if (!changeToSPMDMode(
A,
Changed)) {
4101 HasBuiltStateMachine = buildCustomStateMachine(
A,
Changed);
4103 HasBuiltStateMachine =
false;
4107 ConstantStruct *ExistingKernelEnvC =
4109 ConstantInt *OldUseGenericStateMachineVal =
4110 KernelInfo::getUseGenericStateMachineFromKernelEnvironment(
4111 ExistingKernelEnvC);
4112 if (!HasBuiltStateMachine)
4113 setUseGenericStateMachineOfKernelEnvironment(
4114 OldUseGenericStateMachineVal);
4117 GlobalVariable *KernelEnvGV =
4121 Changed = ChangeStatus::CHANGED;
4127 void insertInstructionGuardsHelper(Attributor &
A) {
4128 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
4130 auto CreateGuardedRegion = [&](
Instruction *RegionStartI,
4132 LoopInfo *LI =
nullptr;
4133 DominatorTree *DT =
nullptr;
4134 MemorySSAUpdater *MSU =
nullptr;
4163 DT, LI, MSU,
"region.guarded.end");
4166 MSU,
"region.barrier");
4169 DT, LI, MSU,
"region.exit");
4171 SplitBlock(ParentBB, RegionStartI, DT, LI, MSU,
"region.guarded");
4174 "Expected a different CFG");
4177 ParentBB, ParentBB->
getTerminator(), DT, LI, MSU,
"region.check.tid");
4180 A.registerManifestAddedBasicBlock(*RegionEndBB);
4181 A.registerManifestAddedBasicBlock(*RegionBarrierBB);
4182 A.registerManifestAddedBasicBlock(*RegionExitBB);
4183 A.registerManifestAddedBasicBlock(*RegionStartBB);
4184 A.registerManifestAddedBasicBlock(*RegionCheckTidBB);
4186 bool HasBroadcastValues =
false;
4189 for (Instruction &
I : *RegionStartBB) {
4191 for (Use &U :
I.uses()) {
4197 if (OutsideUses.
empty())
4200 HasBroadcastValues =
true;
4204 auto *SharedMem =
new GlobalVariable(
4205 M,
I.getType(),
false,
4207 sanitizeForGlobalName(
4208 (
I.getName() +
".guarded.output.alloc").str()),
4210 static_cast<unsigned>(AddressSpace::Shared));
4213 new StoreInst(&
I, SharedMem,
4216 LoadInst *LoadI =
new LoadInst(
4217 I.getType(), SharedMem,
I.getName() +
".guarded.output.load",
4221 for (Use *U : OutsideUses)
4222 A.changeUseAfterManifest(*U, *LoadI);
4225 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
4230 OpenMPIRBuilder::LocationDescription Loc(ParentBB->
end(),
DL);
4232 uint32_t SrcLocStrSize;
4241 OpenMPIRBuilder::LocationDescription LocRegionCheckTid(
4242 RegionCheckTidBB->
end(),
DL);
4244 FunctionCallee HardwareTidFn =
4246 M, OMPRTL___kmpc_get_hardware_thread_id_in_block);
4250 OMPInfoCache.setCallingConvention(HardwareTidFn, Tid);
4252 OMPInfoCache.OMPBuilder.
Builder
4253 .
CreateCondBr(TidCheck, RegionStartBB, RegionBarrierBB)
4258 FunctionCallee BarrierFn =
4260 M, OMPRTL___kmpc_barrier_simple_spmd);
4265 OMPInfoCache.setCallingConvention(BarrierFn, Barrier);
4268 if (HasBroadcastValues) {
4273 OMPInfoCache.setCallingConvention(BarrierFn, Barrier);
4277 auto &AllocSharedRFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
4278 SmallPtrSet<BasicBlock *, 8> Visited;
4279 for (Instruction *GuardedI : SPMDCompatibilityTracker) {
4281 if (!Visited.
insert(BB).second)
4287 while (++IP != IPEnd) {
4288 if (!IP->mayHaveSideEffects() && !IP->mayReadFromMemory())
4291 if (OpenMPOpt::getCallIfRegularCall(*
I, &AllocSharedRFI))
4294 if (isStrictFence(*
I) || !
I->user_empty() ||
4295 !SPMDCompatibilityTracker.contains(
I)) {
4296 LastEffect =
nullptr;
4303 for (
auto &Reorder : Reorders)
4304 Reorder.first->moveBefore(Reorder.second->getIterator());
4309 for (Instruction *GuardedI : SPMDCompatibilityTracker) {
4311 auto *CalleeAA =
A.lookupAAFor<AAKernelInfo>(
4314 assert(CalleeAA !=
nullptr &&
"Expected Callee AAKernelInfo");
4317 if (CalleeAAFunction.getGuardedInstructions().contains(GuardedI))
4320 Instruction *GuardedRegionStart =
nullptr, *GuardedRegionEnd =
nullptr;
4321 for (Instruction &
I : *BB) {
4323 if (isStrictFence(
I)) {
4324 if (SPMDCompatibilityTracker.contains(&
I))
4325 CalleeAAFunction.getGuardedInstructions().insert(&
I);
4326 if (GuardedRegionStart) {
4328 std::make_pair(GuardedRegionStart, GuardedRegionEnd));
4329 GuardedRegionStart =
nullptr;
4330 GuardedRegionEnd =
nullptr;
4337 if (SPMDCompatibilityTracker.contains(&
I)) {
4338 CalleeAAFunction.getGuardedInstructions().insert(&
I);
4339 if (GuardedRegionStart)
4340 GuardedRegionEnd = &
I;
4342 GuardedRegionStart = GuardedRegionEnd = &
I;
4349 if (GuardedRegionStart) {
4351 std::make_pair(GuardedRegionStart, GuardedRegionEnd));
4352 GuardedRegionStart =
nullptr;
4353 GuardedRegionEnd =
nullptr;
4358 for (
auto &GR : GuardedRegions)
4359 CreateGuardedRegion(GR.first, GR.second);
4362 void forceSingleThreadPerWorkgroupHelper(Attributor &
A) {
4371 auto &Ctx = getAnchorValue().getContext();
4378 KernelInitCB->
getNextNode(),
"main.thread.user_code");
4383 A.registerManifestAddedBasicBlock(*InitBB);
4384 A.registerManifestAddedBasicBlock(*UserCodeBB);
4385 A.registerManifestAddedBasicBlock(*ReturnBB);
4394 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
4395 FunctionCallee ThreadIdInBlockFn =
4397 M, OMPRTL___kmpc_get_hardware_thread_id_in_block);
4400 CallInst *ThreadIdInBlock =
4402 OMPInfoCache.setCallingConvention(ThreadIdInBlockFn, ThreadIdInBlock);
4408 ConstantInt::get(ThreadIdInBlock->
getType(), 0),
4409 "thread.is_main", InitBB);
4415 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
4417 if (!SPMDCompatibilityTracker.isAssumed()) {
4418 for (Instruction *NonCompatibleI : SPMDCompatibilityTracker) {
4419 if (!NonCompatibleI)
4424 if (OMPInfoCache.RTLFunctions.contains(CB->getCalledFunction()))
4427 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
4428 ORA <<
"Value has potential side effects preventing SPMD-mode "
4431 ORA <<
". Add `[[omp::assume(\"ompx_spmd_amenable\")]]` to "
4432 "the called function to override";
4436 A.emitRemark<OptimizationRemarkAnalysis>(NonCompatibleI,
"OMP121",
4440 << *NonCompatibleI <<
"\n");
4452 Kernel = CB->getCaller();
4457 ConstantStruct *ExistingKernelEnvC =
4460 KernelInfo::getExecModeFromKernelEnvironment(ExistingKernelEnvC);
4466 Changed = ChangeStatus::CHANGED;
4471 if (mayContainParallelRegion()) {
4472 insertInstructionGuardsHelper(
A);
4474 forceSingleThreadPerWorkgroupHelper(
A);
4475 setMaxThreadsOfKernelEnvironment(
4482 "Initially non-SPMD kernel has SPMD exec mode!");
4483 setExecModeOfKernelEnvironment(
4487 ++NumOpenMPTargetRegionKernelsSPMD;
4491 OMPInfoCache.SPMDizedKernels.insert(
Kernel);
4493 auto Remark = [&](OptimizationRemark
OR) {
4494 return OR <<
"Transformed generic-mode kernel to SPMD-mode.";
4496 A.emitRemark<OptimizationRemark>(KernelInitCB,
"OMP120",
Remark);
4506 if (!ReachedKnownParallelRegions.isValidState())
4509 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
4510 if (!OMPInfoCache.runtimeFnsAvailable({OMPRTL___kmpc_get_max_team_threads,
4511 OMPRTL___kmpc_barrier_simple_generic,
4512 OMPRTL___kmpc_kernel_parallel,
4513 OMPRTL___kmpc_kernel_end_parallel}))
4516 ConstantStruct *ExistingKernelEnvC =
4523 ConstantInt *UseStateMachineC =
4524 KernelInfo::getUseGenericStateMachineFromKernelEnvironment(
4525 ExistingKernelEnvC);
4526 ConstantInt *ModeC =
4527 KernelInfo::getExecModeFromKernelEnvironment(ExistingKernelEnvC);
4532 if (UseStateMachineC->
isZero() ||
4536 Changed = ChangeStatus::CHANGED;
4539 setUseGenericStateMachineOfKernelEnvironment(
4546 if (!mayContainParallelRegion()) {
4547 ++NumOpenMPTargetRegionKernelsWithoutStateMachine;
4549 auto Remark = [&](OptimizationRemark
OR) {
4550 return OR <<
"Removing unused state machine from generic-mode kernel.";
4552 A.emitRemark<OptimizationRemark>(KernelInitCB,
"OMP130",
Remark);
4558 if (ReachedUnknownParallelRegions.empty()) {
4559 ++NumOpenMPTargetRegionKernelsCustomStateMachineWithoutFallback;
4561 auto Remark = [&](OptimizationRemark
OR) {
4562 return OR <<
"Rewriting generic-mode kernel with a customized state "
4565 A.emitRemark<OptimizationRemark>(KernelInitCB,
"OMP131",
Remark);
4567 ++NumOpenMPTargetRegionKernelsCustomStateMachineWithFallback;
4569 auto Remark = [&](OptimizationRemarkAnalysis
OR) {
4570 return OR <<
"Generic-mode kernel is executed with a customized state "
4571 "machine that requires a fallback.";
4573 A.emitRemark<OptimizationRemarkAnalysis>(KernelInitCB,
"OMP132",
Remark);
4576 for (CallBase *UnknownParallelRegionCB : ReachedUnknownParallelRegions) {
4577 if (!UnknownParallelRegionCB)
4579 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
4580 return ORA <<
"Call may contain unknown parallel regions. Use "
4581 <<
"`[[omp::assume(\"omp_no_parallelism\")]]` to "
4584 A.emitRemark<OptimizationRemarkAnalysis>(UnknownParallelRegionCB,
4617 auto &Ctx = getAnchorValue().getContext();
4621 BasicBlock *InitBB = KernelInitCB->getParent();
4623 KernelInitCB->getNextNode(),
"thread.user_code.check");
4627 Ctx,
"worker_state_machine.begin",
Kernel, UserCodeEntryBB);
4629 Ctx,
"worker_state_machine.finished",
Kernel, UserCodeEntryBB);
4631 Ctx,
"worker_state_machine.is_active.check",
Kernel, UserCodeEntryBB);
4634 Kernel, UserCodeEntryBB);
4637 Kernel, UserCodeEntryBB);
4639 Ctx,
"worker_state_machine.done.barrier",
Kernel, UserCodeEntryBB);
4640 A.registerManifestAddedBasicBlock(*InitBB);
4641 A.registerManifestAddedBasicBlock(*UserCodeEntryBB);
4642 A.registerManifestAddedBasicBlock(*IsWorkerCheckBB);
4643 A.registerManifestAddedBasicBlock(*StateMachineBeginBB);
4644 A.registerManifestAddedBasicBlock(*StateMachineFinishedBB);
4645 A.registerManifestAddedBasicBlock(*StateMachineIsActiveCheckBB);
4646 A.registerManifestAddedBasicBlock(*StateMachineIfCascadeCurrentBB);
4647 A.registerManifestAddedBasicBlock(*StateMachineEndParallelBB);
4648 A.registerManifestAddedBasicBlock(*StateMachineDoneBarrierBB);
4650 const DebugLoc &DLoc = KernelInitCB->getDebugLoc();
4656 ConstantInt::getAllOnesValue(KernelInitCB->getType()),
4657 "thread.is_worker", InitBB);
4666 FunctionCallee MaxTeamThreadsFn =
4668 M, OMPRTL___kmpc_get_max_team_threads);
4669 Constant *IsSPMDArg = ConstantInt::get(OMPInfoCache.OMPBuilder.Int32, 0);
4671 MaxTeamThreadsFn, {IsSPMDArg},
"max_team_threads", IsWorkerCheckBB);
4672 OMPInfoCache.setCallingConvention(MaxTeamThreadsFn, MaxTeamThreads);
4676 "thread.is_main_or_worker", IsWorkerCheckBB);
4679 StateMachineFinishedBB, IsWorkerCheckBB);
4682 const DataLayout &
DL =
M.getDataLayout();
4683 Type *VoidPtrTy = PointerType::getUnqual(Ctx);
4685 new AllocaInst(VoidPtrTy,
DL.getAllocaAddrSpace(),
nullptr,
4690 OpenMPIRBuilder::LocationDescription(StateMachineBeginBB->
end(), DLoc));
4692 Value *Ident = KernelInfo::getIdentFromKernelEnvironment(KernelEnvC);
4693 Value *GTid = KernelInitCB;
4695 FunctionCallee BarrierFn =
4697 M, OMPRTL___kmpc_barrier_simple_generic);
4700 OMPInfoCache.setCallingConvention(BarrierFn, Barrier);
4704 (
unsigned int)AddressSpace::Generic) {
4705 WorkFnAI =
new AddrSpaceCastInst(
4706 WorkFnAI, PointerType::get(Ctx, (
unsigned int)AddressSpace::Generic),
4707 WorkFnAI->
getName() +
".generic", StateMachineBeginBB);
4711 FunctionCallee KernelParallelFn =
4713 M, OMPRTL___kmpc_kernel_parallel);
4715 KernelParallelFn, {WorkFnAI},
"worker.is_active", StateMachineBeginBB);
4716 OMPInfoCache.setCallingConvention(KernelParallelFn, IsActiveWorker);
4718 Instruction *WorkFn =
new LoadInst(VoidPtrTy, WorkFnAI,
"worker.work_fn",
4719 StateMachineBeginBB);
4722 FunctionType *ParallelRegionFnTy = FunctionType::get(
4723 Type::getVoidTy(Ctx), {Type::getInt16Ty(Ctx), Type::getInt32Ty(Ctx)},
4729 StateMachineBeginBB);
4730 IsDone->setDebugLoc(DLoc);
4732 StateMachineIsActiveCheckBB, StateMachineBeginBB)
4736 StateMachineDoneBarrierBB, StateMachineIsActiveCheckBB)
4742 const unsigned int WrapperFunctionArgNo = 6;
4747 for (
int I = 0,
E = ReachedKnownParallelRegions.size();
I <
E; ++
I) {
4748 auto *CB = ReachedKnownParallelRegions[
I];
4750 CB->getArgOperand(WrapperFunctionArgNo)->stripPointerCasts());
4752 Ctx,
"worker_state_machine.parallel_region.execute",
Kernel,
4753 StateMachineEndParallelBB);
4755 ->setDebugLoc(DLoc);
4761 Kernel, StateMachineEndParallelBB);
4762 A.registerManifestAddedBasicBlock(*PRExecuteBB);
4763 A.registerManifestAddedBasicBlock(*PRNextBB);
4768 if (
I + 1 <
E || !ReachedUnknownParallelRegions.empty()) {
4771 "worker.check_parallel_region", StateMachineIfCascadeCurrentBB);
4779 StateMachineIfCascadeCurrentBB)
4781 StateMachineIfCascadeCurrentBB = PRNextBB;
4787 if (!ReachedUnknownParallelRegions.empty()) {
4788 StateMachineIfCascadeCurrentBB->
setName(
4789 "worker_state_machine.parallel_region.fallback.execute");
4791 StateMachineIfCascadeCurrentBB)
4792 ->setDebugLoc(DLoc);
4795 StateMachineIfCascadeCurrentBB)
4798 FunctionCallee EndParallelFn =
4800 M, OMPRTL___kmpc_kernel_end_parallel);
4801 CallInst *EndParallel =
4803 OMPInfoCache.setCallingConvention(EndParallelFn, EndParallel);
4809 ->setDebugLoc(DLoc);
4819 KernelInfoState StateBefore = getState();
4825 struct UpdateKernelEnvCRAII {
4826 AAKernelInfoFunction &AA;
4828 UpdateKernelEnvCRAII(AAKernelInfoFunction &AA) : AA(AA) {}
4830 ~UpdateKernelEnvCRAII() {
4834 ConstantStruct *ExistingKernelEnvC =
4837 if (!AA.isValidState()) {
4838 AA.KernelEnvC = ExistingKernelEnvC;
4842 if (!AA.ReachedKnownParallelRegions.isValidState())
4843 AA.setUseGenericStateMachineOfKernelEnvironment(
4844 KernelInfo::getUseGenericStateMachineFromKernelEnvironment(
4845 ExistingKernelEnvC));
4847 if (!AA.SPMDCompatibilityTracker.isValidState())
4848 AA.setExecModeOfKernelEnvironment(
4849 KernelInfo::getExecModeFromKernelEnvironment(ExistingKernelEnvC));
4851 ConstantInt *MayUseNestedParallelismC =
4852 KernelInfo::getMayUseNestedParallelismFromKernelEnvironment(
4854 ConstantInt *NewMayUseNestedParallelismC = ConstantInt::get(
4855 MayUseNestedParallelismC->
getIntegerType(), AA.NestedParallelism);
4856 AA.setMayUseNestedParallelismOfKernelEnvironment(
4857 NewMayUseNestedParallelismC);
4867 if (!
I.mayWriteToMemory())
4870 const auto *UnderlyingObjsAA =
A.getAAFor<AAUnderlyingObjects>(
4872 DepClassTy::OPTIONAL);
4873 auto *
HS =
A.getAAFor<AAHeapToStack>(
4875 DepClassTy::OPTIONAL);
4876 if (UnderlyingObjsAA &&
4877 UnderlyingObjsAA->forallUnderlyingObjects([&](
Value &Obj) {
4878 if (AA::isAssumedThreadLocalObject(A, Obj, *this))
4882 auto *CB = dyn_cast<CallBase>(&Obj);
4883 return CB && HS && HS->isAssumedHeapToStack(*CB);
4889 SPMDCompatibilityTracker.insert(&
I);
4893 bool UsedAssumedInformationInCheckRWInst =
false;
4894 if (!SPMDCompatibilityTracker.isAtFixpoint())
4895 if (!
A.checkForAllReadWriteInstructions(
4896 CheckRWInst, *
this, UsedAssumedInformationInCheckRWInst))
4897 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
4899 bool UsedAssumedInformationFromReachingKernels =
false;
4900 if (!IsKernelEntry) {
4901 updateParallelLevels(
A);
4903 bool AllReachingKernelsKnown =
true;
4904 updateReachingKernelEntries(
A, AllReachingKernelsKnown);
4905 UsedAssumedInformationFromReachingKernels = !AllReachingKernelsKnown;
4907 if (!SPMDCompatibilityTracker.empty()) {
4908 if (!ParallelLevels.isValidState())
4909 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
4910 else if (!ReachingKernelEntries.isValidState())
4911 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
4917 for (
auto *
Kernel : ReachingKernelEntries) {
4918 auto *CBAA =
A.getAAFor<AAKernelInfo>(
4920 if (CBAA && CBAA->SPMDCompatibilityTracker.isValidState() &&
4921 CBAA->SPMDCompatibilityTracker.isAssumed())
4925 if (!CBAA || !CBAA->SPMDCompatibilityTracker.isAtFixpoint())
4926 UsedAssumedInformationFromReachingKernels =
true;
4928 if (SPMD != 0 &&
Generic != 0)
4929 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
4935 bool AllParallelRegionStatesWereFixed =
true;
4936 bool AllSPMDStatesWereFixed =
true;
4943 if (
Function *Callback = OMPInformationCache::getAnalyzableCallback(CB)) {
4945 <<
Callback->getName() <<
" of " << CB <<
"\n");
4946 if (
auto *CallbackAA =
A.getAAFor<AAKernelInfo>(
4948 getState() ^= CallbackAA->getState();
4949 AllSPMDStatesWereFixed &=
4950 CallbackAA->SPMDCompatibilityTracker.isAtFixpoint();
4951 AllParallelRegionStatesWereFixed &=
4952 CallbackAA->ReachedKnownParallelRegions.isAtFixpoint();
4953 AllParallelRegionStatesWereFixed &=
4954 CallbackAA->ReachedUnknownParallelRegions.isAtFixpoint();
4957 auto *CBAA =
A.getAAFor<AAKernelInfo>(
4961 getState() ^= CBAA->getState();
4962 AllSPMDStatesWereFixed &= CBAA->SPMDCompatibilityTracker.isAtFixpoint();
4963 AllParallelRegionStatesWereFixed &=
4964 CBAA->ReachedKnownParallelRegions.isAtFixpoint();
4965 AllParallelRegionStatesWereFixed &=
4966 CBAA->ReachedUnknownParallelRegions.isAtFixpoint();
4970 bool UsedAssumedInformationInCheckCallInst =
false;
4971 if (!
A.checkForAllCallLikeInstructions(
4972 CheckCallInst, *
this, UsedAssumedInformationInCheckCallInst)) {
4974 <<
"Failed to visit all call-like instructions!\n";);
4975 return indicatePessimisticFixpoint();
4980 if (!UsedAssumedInformationInCheckCallInst &&
4981 AllParallelRegionStatesWereFixed) {
4982 ReachedKnownParallelRegions.indicateOptimisticFixpoint();
4983 ReachedUnknownParallelRegions.indicateOptimisticFixpoint();
4988 if (!UsedAssumedInformationInCheckRWInst &&
4989 !UsedAssumedInformationInCheckCallInst &&
4990 !UsedAssumedInformationFromReachingKernels && AllSPMDStatesWereFixed)
4991 SPMDCompatibilityTracker.indicateOptimisticFixpoint();
4993 return StateBefore == getState() ? ChangeStatus::UNCHANGED
4994 : ChangeStatus::CHANGED;
4999 void updateReachingKernelEntries(Attributor &
A,
5000 bool &AllReachingKernelsKnown) {
5001 auto PredCallSite = [&](AbstractCallSite ACS) {
5004 assert(Caller &&
"Caller is nullptr");
5006 auto *CAA =
A.getOrCreateAAFor<AAKernelInfo>(
5008 if (CAA && CAA->ReachingKernelEntries.isValidState()) {
5009 ReachingKernelEntries ^= CAA->ReachingKernelEntries;
5015 ReachingKernelEntries.indicatePessimisticFixpoint();
5020 if (!
A.checkForAllCallSites(PredCallSite, *
this,
5022 AllReachingKernelsKnown))
5023 ReachingKernelEntries.indicatePessimisticFixpoint();
5027 void updateParallelLevels(Attributor &
A) {
5028 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
5029 OMPInformationCache::RuntimeFunctionInfo &Parallel60RFI =
5030 OMPInfoCache.RFIs[OMPRTL___kmpc_parallel_60];
5032 auto PredCallSite = [&](AbstractCallSite ACS) {
5035 assert(Caller &&
"Caller is nullptr");
5039 if (CAA && CAA->ParallelLevels.isValidState()) {
5045 if (Caller == Parallel60RFI.Declaration) {
5046 ParallelLevels.indicatePessimisticFixpoint();
5050 ParallelLevels ^= CAA->ParallelLevels;
5057 ParallelLevels.indicatePessimisticFixpoint();
5062 bool AllCallSitesKnown =
true;
5063 if (!
A.checkForAllCallSites(PredCallSite, *
this,
5066 ParallelLevels.indicatePessimisticFixpoint();
5073struct AAKernelInfoCallSite : AAKernelInfo {
5074 AAKernelInfoCallSite(
const IRPosition &IRP, Attributor &
A)
5075 : AAKernelInfo(IRP,
A) {}
5078 AAKernelInfo::initialize(
A);
5081 auto *AssumptionAA =
A.getAAFor<AAAssumptionInfo>(
5085 if (AssumptionAA && AssumptionAA->hasAssumption(
"ompx_spmd_amenable")) {
5086 indicateOptimisticFixpoint();
5094 indicateOptimisticFixpoint();
5103 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
5104 const auto &It = OMPInfoCache.RuntimeFunctionIDMap.find(Callee);
5105 if (It == OMPInfoCache.RuntimeFunctionIDMap.end()) {
5107 if (!Callee || !
A.isFunctionIPOAmendable(*Callee)) {
5111 if (!AssumptionAA ||
5112 !(AssumptionAA->hasAssumption(
"omp_no_openmp") ||
5113 AssumptionAA->hasAssumption(
"omp_no_parallelism")))
5114 ReachedUnknownParallelRegions.insert(&CB);
5118 if (!SPMDCompatibilityTracker.isAtFixpoint()) {
5119 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5120 SPMDCompatibilityTracker.insert(&CB);
5125 indicateOptimisticFixpoint();
5134 if (NumCallees > 1 && !
Callee->hasMetadata(LLVMContext::MD_callback)) {
5135 indicatePessimisticFixpoint();
5142 case OMPRTL___kmpc_is_spmd_exec_mode:
5143 case OMPRTL___kmpc_distribute_static_fini:
5144 case OMPRTL___kmpc_for_static_fini:
5145 case OMPRTL___kmpc_global_thread_num:
5146 case OMPRTL___kmpc_get_hardware_num_threads_in_block:
5147 case OMPRTL___kmpc_get_hardware_num_blocks:
5148 case OMPRTL___kmpc_single:
5149 case OMPRTL___kmpc_end_single:
5150 case OMPRTL___kmpc_master:
5151 case OMPRTL___kmpc_end_master:
5152 case OMPRTL___kmpc_barrier:
5153 case OMPRTL___kmpc_nvptx_parallel_reduce_nowait_v2:
5154 case OMPRTL___kmpc_gpu_xteam_reduce_nowait:
5155 case OMPRTL___kmpc_error:
5156 case OMPRTL___kmpc_flush:
5157 case OMPRTL___kmpc_get_hardware_thread_id_in_block:
5158 case OMPRTL___kmpc_get_warp_size:
5159 case OMPRTL_omp_get_thread_num:
5160 case OMPRTL_omp_get_num_threads:
5161 case OMPRTL_omp_get_max_threads:
5162 case OMPRTL_omp_in_parallel:
5163 case OMPRTL_omp_get_dynamic:
5164 case OMPRTL_omp_get_cancellation:
5165 case OMPRTL_omp_get_nested:
5166 case OMPRTL_omp_get_schedule:
5167 case OMPRTL_omp_get_thread_limit:
5168 case OMPRTL_omp_get_supported_active_levels:
5169 case OMPRTL_omp_get_max_active_levels:
5170 case OMPRTL_omp_get_level:
5171 case OMPRTL_omp_get_ancestor_thread_num:
5172 case OMPRTL_omp_get_team_size:
5173 case OMPRTL_omp_get_active_level:
5174 case OMPRTL_omp_in_final:
5175 case OMPRTL_omp_get_proc_bind:
5176 case OMPRTL_omp_get_num_places:
5177 case OMPRTL_omp_get_num_procs:
5178 case OMPRTL_omp_get_place_proc_ids:
5179 case OMPRTL_omp_get_place_num:
5180 case OMPRTL_omp_get_partition_num_places:
5181 case OMPRTL_omp_get_partition_place_nums:
5182 case OMPRTL_omp_get_wtime:
5184 case OMPRTL___kmpc_distribute_static_init_4:
5185 case OMPRTL___kmpc_distribute_static_init_4u:
5186 case OMPRTL___kmpc_distribute_static_init_8:
5187 case OMPRTL___kmpc_distribute_static_init_8u:
5188 case OMPRTL___kmpc_for_static_init_4:
5189 case OMPRTL___kmpc_for_static_init_4u:
5190 case OMPRTL___kmpc_for_static_init_8:
5191 case OMPRTL___kmpc_for_static_init_8u: {
5193 unsigned ScheduleArgOpNo = 2;
5194 auto *ScheduleTypeCI =
5196 unsigned ScheduleTypeVal =
5197 ScheduleTypeCI ? ScheduleTypeCI->getZExtValue() : 0;
5199 case OMPScheduleType::UnorderedStatic:
5200 case OMPScheduleType::UnorderedStaticChunked:
5201 case OMPScheduleType::OrderedDistribute:
5202 case OMPScheduleType::OrderedDistributeChunked:
5205 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5206 SPMDCompatibilityTracker.insert(&CB);
5210 case OMPRTL___kmpc_target_init:
5213 case OMPRTL___kmpc_target_deinit:
5214 KernelDeinitCB = &CB;
5216 case OMPRTL___kmpc_parallel_60:
5217 if (!handleParallel60(
A, CB))
5218 indicatePessimisticFixpoint();
5220 case OMPRTL___kmpc_omp_task:
5222 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5223 SPMDCompatibilityTracker.insert(&CB);
5224 ReachedUnknownParallelRegions.insert(&CB);
5226 case OMPRTL___kmpc_alloc_shared:
5227 case OMPRTL___kmpc_free_shared:
5235 case OMPRTL___kmpc_distribute_static_loop_4:
5236 case OMPRTL___kmpc_distribute_static_loop_4u:
5237 case OMPRTL___kmpc_distribute_static_loop_8:
5238 case OMPRTL___kmpc_distribute_static_loop_8u:
5246 if (!OMPInformationCache::getAnalyzableCallback(CB))
5247 ReachedUnknownParallelRegions.insert(&CB);
5248 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5249 SPMDCompatibilityTracker.insert(&CB);
5251 case OMPRTL___kmpc_distribute_for_static_loop_4:
5252 case OMPRTL___kmpc_distribute_for_static_loop_4u:
5253 case OMPRTL___kmpc_distribute_for_static_loop_8:
5254 case OMPRTL___kmpc_distribute_for_static_loop_8u:
5255 case OMPRTL___kmpc_for_static_loop_4:
5256 case OMPRTL___kmpc_for_static_loop_4u:
5257 case OMPRTL___kmpc_for_static_loop_8:
5258 case OMPRTL___kmpc_for_static_loop_8u:
5267 if (!OMPInformationCache::getAnalyzableCallback(CB))
5268 ReachedUnknownParallelRegions.insert(&CB);
5269 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5270 SPMDCompatibilityTracker.insert(&CB);
5275 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5276 SPMDCompatibilityTracker.insert(&CB);
5282 indicateOptimisticFixpoint();
5286 A.getAAFor<AACallEdges>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
5287 if (!AACE || !AACE->getState().isValidState() || AACE->hasUnknownCallee()) {
5288 CheckCallee(getAssociatedFunction(), 1);
5291 const auto &OptimisticEdges = AACE->getOptimisticEdges();
5292 for (
auto *Callee : OptimisticEdges) {
5293 CheckCallee(Callee, OptimisticEdges.size());
5304 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
5305 KernelInfoState StateBefore = getState();
5307 auto CheckCallee = [&](
Function *
F,
int NumCallees) {
5308 const auto &It = OMPInfoCache.RuntimeFunctionIDMap.find(
F);
5312 if (It == OMPInfoCache.RuntimeFunctionIDMap.end()) {
5315 A.getAAFor<AAKernelInfo>(*
this, FnPos, DepClassTy::REQUIRED);
5317 return indicatePessimisticFixpoint();
5318 if (getState() == FnAA->getState())
5319 return ChangeStatus::UNCHANGED;
5320 getState() = FnAA->getState();
5321 return ChangeStatus::CHANGED;
5325 if (NumCallees > 1 && !
F->hasMetadata(LLVMContext::MD_callback))
5326 return indicatePessimisticFixpoint();
5329 if (It->getSecond() == OMPRTL___kmpc_parallel_60) {
5330 if (!handleParallel60(
A, CB))
5331 return indicatePessimisticFixpoint();
5332 return StateBefore == getState() ? ChangeStatus::UNCHANGED
5333 : ChangeStatus::CHANGED;
5339 (It->getSecond() == OMPRTL___kmpc_alloc_shared ||
5340 It->getSecond() == OMPRTL___kmpc_free_shared) &&
5341 "Expected a __kmpc_alloc_shared or __kmpc_free_shared runtime call");
5343 auto *HeapToStackAA =
A.getAAFor<AAHeapToStack>(
5345 auto *HeapToSharedAA =
A.getAAFor<AAHeapToShared>(
5353 case OMPRTL___kmpc_alloc_shared:
5354 if ((!HeapToStackAA || !HeapToStackAA->isAssumedHeapToStack(CB)) &&
5355 (!HeapToSharedAA || !HeapToSharedAA->isAssumedHeapToShared(CB)))
5356 SPMDCompatibilityTracker.insert(&CB);
5358 case OMPRTL___kmpc_free_shared:
5359 if ((!HeapToStackAA ||
5360 !HeapToStackAA->isAssumedHeapToStackRemovedFree(CB)) &&
5362 !HeapToSharedAA->isAssumedHeapToSharedRemovedFree(CB)))
5363 SPMDCompatibilityTracker.insert(&CB);
5366 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5367 SPMDCompatibilityTracker.insert(&CB);
5369 return ChangeStatus::CHANGED;
5373 A.getAAFor<AACallEdges>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
5374 if (!AACE || !AACE->getState().isValidState() || AACE->hasUnknownCallee()) {
5375 if (
Function *
F = getAssociatedFunction())
5378 const auto &OptimisticEdges = AACE->getOptimisticEdges();
5379 for (
auto *Callee : OptimisticEdges) {
5380 CheckCallee(Callee, OptimisticEdges.size());
5386 return StateBefore == getState() ? ChangeStatus::UNCHANGED
5387 : ChangeStatus::CHANGED;
5392 bool handleParallel60(Attributor &
A, CallBase &CB) {
5393 const unsigned int NonWrapperFunctionArgNo = 5;
5394 const unsigned int WrapperFunctionArgNo = 6;
5395 auto ParallelRegionOpArgNo = SPMDCompatibilityTracker.isAssumed()
5396 ? NonWrapperFunctionArgNo
5397 : WrapperFunctionArgNo;
5401 if (!ParallelRegion)
5404 ReachedKnownParallelRegions.insert(&CB);
5406 auto *FnAA =
A.getAAFor<AAKernelInfo>(
5408 NestedParallelism |= !FnAA || !FnAA->getState().isValidState() ||
5409 !FnAA->ReachedKnownParallelRegions.empty() ||
5410 !FnAA->ReachedKnownParallelRegions.isValidState() ||
5411 !FnAA->ReachedUnknownParallelRegions.isValidState() ||
5412 !FnAA->ReachedUnknownParallelRegions.empty();
5417struct AAFoldRuntimeCall
5418 :
public StateWrapper<BooleanState, AbstractAttribute> {
5419 using Base = StateWrapper<BooleanState, AbstractAttribute>;
5421 AAFoldRuntimeCall(
const IRPosition &IRP, Attributor &
A) :
Base(IRP) {}
5424 void trackStatistics()
const override {}
5427 static AAFoldRuntimeCall &createForPosition(
const IRPosition &IRP,
5430 StringRef
getName()
const override {
return "AAFoldRuntimeCall"; }
5432 const char *getIdAddr()
const override {
return &ID; }
5436 static bool classof(
const AbstractAttribute *AA) {
5440 static const char ID;
5443struct AAFoldRuntimeCallCallSiteReturned : AAFoldRuntimeCall {
5444 AAFoldRuntimeCallCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5445 : AAFoldRuntimeCall(IRP,
A) {}
5447 const std::string getAsStr(Attributor *)
const override {
5448 if (!isValidState())
5451 std::string Str(
"simplified value: ");
5453 if (!SimplifiedValue)
5454 return Str + std::string(
"none");
5456 if (!*SimplifiedValue)
5457 return Str + std::string(
"nullptr");
5460 return Str + std::to_string(CI->getSExtValue());
5462 return Str + std::string(
"unknown");
5467 indicatePessimisticFixpoint();
5471 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
5472 const auto &It = OMPInfoCache.RuntimeFunctionIDMap.find(Callee);
5473 assert(It != OMPInfoCache.RuntimeFunctionIDMap.end() &&
5474 "Expected a known OpenMP runtime function");
5476 RFKind = It->getSecond();
5479 A.registerSimplificationCallback(
5481 [&](
const IRPosition &IRP,
const AbstractAttribute *AA,
5482 bool &UsedAssumedInformation) -> std::optional<Value *> {
5483 assert((isValidState() || SimplifiedValue ==
nullptr) &&
5484 "Unexpected invalid state!");
5486 if (!isAtFixpoint()) {
5487 UsedAssumedInformation =
true;
5489 A.recordDependence(*
this, *AA, DepClassTy::OPTIONAL);
5491 return SimplifiedValue;
5498 case OMPRTL___kmpc_is_spmd_exec_mode:
5501 case OMPRTL___kmpc_parallel_level:
5504 case OMPRTL___kmpc_get_hardware_num_threads_in_block:
5505 Changed =
Changed | foldKernelFnAttribute(
A,
"omp_target_thread_limit");
5507 case OMPRTL___kmpc_get_hardware_num_blocks:
5520 if (SimplifiedValue && *SimplifiedValue) {
5523 A.deleteAfterManifest(
I);
5526 auto Remark = [&](OptimizationRemark
OR) {
5528 return OR <<
"Replacing OpenMP runtime call "
5530 <<
ore::NV(
"FoldedValue",
C->getZExtValue()) <<
".";
5531 return OR <<
"Replacing OpenMP runtime call "
5536 A.emitRemark<OptimizationRemark>(CB,
"OMP180",
Remark);
5539 << **SimplifiedValue <<
"\n");
5541 Changed = ChangeStatus::CHANGED;
5548 SimplifiedValue =
nullptr;
5549 return AAFoldRuntimeCall::indicatePessimisticFixpoint();
5555 std::optional<Value *> SimplifiedValueBefore = SimplifiedValue;
5557 unsigned AssumedSPMDCount = 0, KnownSPMDCount = 0;
5558 unsigned AssumedNonSPMDCount = 0, KnownNonSPMDCount = 0;
5559 auto *CallerKernelInfoAA =
A.getAAFor<AAKernelInfo>(
5562 if (!CallerKernelInfoAA ||
5563 !CallerKernelInfoAA->ReachingKernelEntries.isValidState())
5564 return indicatePessimisticFixpoint();
5566 for (
Kernel K : CallerKernelInfoAA->ReachingKernelEntries) {
5568 DepClassTy::REQUIRED);
5570 if (!AA || !AA->isValidState()) {
5571 SimplifiedValue =
nullptr;
5572 return indicatePessimisticFixpoint();
5575 if (AA->SPMDCompatibilityTracker.isAssumed()) {
5576 if (AA->SPMDCompatibilityTracker.isAtFixpoint())
5581 if (AA->SPMDCompatibilityTracker.isAtFixpoint())
5582 ++KnownNonSPMDCount;
5584 ++AssumedNonSPMDCount;
5588 if ((AssumedSPMDCount + KnownSPMDCount) &&
5589 (AssumedNonSPMDCount + KnownNonSPMDCount))
5590 return indicatePessimisticFixpoint();
5592 auto &Ctx = getAnchorValue().getContext();
5593 if (KnownSPMDCount || AssumedSPMDCount) {
5594 assert(KnownNonSPMDCount == 0 && AssumedNonSPMDCount == 0 &&
5595 "Expected only SPMD kernels!");
5598 SimplifiedValue = ConstantInt::get(Type::getInt8Ty(Ctx),
true);
5599 }
else if (KnownNonSPMDCount || AssumedNonSPMDCount) {
5600 assert(KnownSPMDCount == 0 && AssumedSPMDCount == 0 &&
5601 "Expected only non-SPMD kernels!");
5604 SimplifiedValue = ConstantInt::get(Type::getInt8Ty(Ctx),
false);
5609 assert(!SimplifiedValue &&
"SimplifiedValue should be none");
5612 return SimplifiedValue == SimplifiedValueBefore ? ChangeStatus::UNCHANGED
5613 : ChangeStatus::CHANGED;
5618 std::optional<Value *> SimplifiedValueBefore = SimplifiedValue;
5620 auto *CallerKernelInfoAA =
A.getAAFor<AAKernelInfo>(
5623 if (!CallerKernelInfoAA ||
5624 !CallerKernelInfoAA->ParallelLevels.isValidState())
5625 return indicatePessimisticFixpoint();
5627 if (!CallerKernelInfoAA->ReachingKernelEntries.isValidState())
5628 return indicatePessimisticFixpoint();
5630 if (CallerKernelInfoAA->ReachingKernelEntries.empty()) {
5631 assert(!SimplifiedValue &&
5632 "SimplifiedValue should keep none at this point");
5633 return ChangeStatus::UNCHANGED;
5636 unsigned AssumedSPMDCount = 0, KnownSPMDCount = 0;
5637 unsigned AssumedNonSPMDCount = 0, KnownNonSPMDCount = 0;
5638 for (
Kernel K : CallerKernelInfoAA->ReachingKernelEntries) {
5640 DepClassTy::REQUIRED);
5641 if (!AA || !AA->SPMDCompatibilityTracker.isValidState())
5642 return indicatePessimisticFixpoint();
5644 if (AA->SPMDCompatibilityTracker.isAssumed()) {
5645 if (AA->SPMDCompatibilityTracker.isAtFixpoint())
5650 if (AA->SPMDCompatibilityTracker.isAtFixpoint())
5651 ++KnownNonSPMDCount;
5653 ++AssumedNonSPMDCount;
5657 if ((AssumedSPMDCount + KnownSPMDCount) &&
5658 (AssumedNonSPMDCount + KnownNonSPMDCount))
5659 return indicatePessimisticFixpoint();
5661 auto &Ctx = getAnchorValue().getContext();
5665 if (AssumedSPMDCount || KnownSPMDCount) {
5666 assert(KnownNonSPMDCount == 0 && AssumedNonSPMDCount == 0 &&
5667 "Expected only SPMD kernels!");
5668 SimplifiedValue = ConstantInt::get(Type::getInt8Ty(Ctx), 1);
5670 assert(KnownSPMDCount == 0 && AssumedSPMDCount == 0 &&
5671 "Expected only non-SPMD kernels!");
5672 SimplifiedValue = ConstantInt::get(Type::getInt8Ty(Ctx), 0);
5674 return SimplifiedValue == SimplifiedValueBefore ? ChangeStatus::UNCHANGED
5675 : ChangeStatus::CHANGED;
5678 ChangeStatus foldKernelFnAttribute(Attributor &
A, llvm::StringRef Attr) {
5680 int32_t CurrentAttrValue = -1;
5681 std::optional<Value *> SimplifiedValueBefore = SimplifiedValue;
5683 auto *CallerKernelInfoAA =
A.getAAFor<AAKernelInfo>(
5686 if (!CallerKernelInfoAA ||
5687 !CallerKernelInfoAA->ReachingKernelEntries.isValidState())
5688 return indicatePessimisticFixpoint();
5691 for (
Kernel K : CallerKernelInfoAA->ReachingKernelEntries) {
5692 int32_t NextAttrVal =
K->getFnAttributeAsParsedInteger(Attr, -1);
5694 if (NextAttrVal == -1 ||
5695 (CurrentAttrValue != -1 && CurrentAttrValue != NextAttrVal))
5696 return indicatePessimisticFixpoint();
5697 CurrentAttrValue = NextAttrVal;
5700 if (CurrentAttrValue != -1) {
5701 auto &Ctx = getAnchorValue().getContext();
5703 ConstantInt::get(Type::getInt32Ty(Ctx), CurrentAttrValue);
5705 return SimplifiedValue == SimplifiedValueBefore ? ChangeStatus::UNCHANGED
5706 : ChangeStatus::CHANGED;
5712 std::optional<Value *> SimplifiedValue;
5722 auto &RFI = OMPInfoCache.RFIs[RF];
5723 RFI.foreachUse(SCC, [&](Use &U,
Function &
F) {
5724 CallInst *CI = OpenMPOpt::getCallIfRegularCall(U, &RFI);
5727 A.getOrCreateAAFor<AAFoldRuntimeCall>(
5729 DepClassTy::NONE,
false,
5735void OpenMPOpt::registerAAs(
bool IsModulePass) {
5745 A.getOrCreateAAFor<AAKernelInfo>(
5747 DepClassTy::NONE,
false,
5751 OMPInformationCache::RuntimeFunctionInfo &InitRFI =
5752 OMPInfoCache.RFIs[OMPRTL___kmpc_target_init];
5753 InitRFI.foreachUse(SCC, CreateKernelInfoCB);
5755 registerFoldRuntimeCall(OMPRTL___kmpc_is_spmd_exec_mode);
5756 registerFoldRuntimeCall(OMPRTL___kmpc_parallel_level);
5757 registerFoldRuntimeCall(OMPRTL___kmpc_get_hardware_num_threads_in_block);
5758 registerFoldRuntimeCall(OMPRTL___kmpc_get_hardware_num_blocks);
5763 for (
int Idx = 0;
Idx < OMPInfoCache.ICVs.size() - 1; ++
Idx) {
5766 auto &GetterRFI = OMPInfoCache.RFIs[ICVInfo.Getter];
5769 CallInst *CI = OpenMPOpt::getCallIfRegularCall(U, &GetterRFI);
5776 A.getOrCreateAAFor<AAICVTracker>(CBPos);
5780 GetterRFI.foreachUse(SCC, CreateAA);
5789 for (
auto *
F : SCC) {
5790 if (
F->isDeclaration())
5796 if (
F->hasLocalLinkage()) {
5798 const auto *CB = dyn_cast<CallBase>(U.getUser());
5799 return CB && CB->isCallee(&U) &&
5800 A.isRunOn(const_cast<Function *>(CB->getCaller()));
5804 registerAAsForFunction(
A, *
F);
5808void OpenMPOpt::registerAAsForFunction(Attributor &
A,
const Function &
F) {
5809 auto &OMPInfoCache =
static_cast<OMPInformationCache &
>(
A.getInfoCache());
5812 A.getOrCreateAAFor<AAExecutionDomain>(FPos);
5813 if (
F.hasFnAttribute(Attribute::Convergent))
5814 A.getOrCreateAAFor<AANonConvergent>(FPos);
5816 bool FunctionUsesSharedAlloc =
false;
5818 const OMPInformationCache::RuntimeFunctionInfo::UseVector *SharedAllocUses =
5819 OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared].getUseVector(
5821 FunctionUsesSharedAlloc = SharedAllocUses && !SharedAllocUses->
empty();
5823 bool HasHeapToStackCandidate =
false;
5824 const TargetLibraryInfo *TLI =
nullptr;
5828 bool UsedAssumedInformation =
false;
5831 A.getOrCreateAAFor<AAAddressSpace>(
5838 TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(
F);
5839 HasHeapToStackCandidate =
5843 A.getOrCreateAAFor<AAIndirectCallInfo>(
5848 A.getOrCreateAAFor<AAAddressSpace>(
5857 if (
II->getIntrinsicID() == Intrinsic::assume) {
5858 A.getOrCreateAAFor<AAPotentialValues>(
5865 if (FunctionUsesSharedAlloc)
5866 A.getOrCreateAAFor<AAHeapToShared>(FPos);
5867 if (HasHeapToStackCandidate)
5868 A.getOrCreateAAFor<AAHeapToStack>(FPos);
5871const char AAICVTracker::ID = 0;
5872const char AAKernelInfo::ID = 0;
5874const char AAHeapToShared::ID = 0;
5875const char AAFoldRuntimeCall::ID = 0;
5877AAICVTracker &AAICVTracker::createForPosition(
const IRPosition &IRP,
5879 AAICVTracker *AA =
nullptr;
5887 AA =
new (
A.Allocator) AAICVTrackerFunctionReturned(IRP,
A);
5890 AA =
new (
A.Allocator) AAICVTrackerCallSiteReturned(IRP,
A);
5893 AA =
new (
A.Allocator) AAICVTrackerCallSite(IRP,
A);
5896 AA =
new (
A.Allocator) AAICVTrackerFunction(IRP,
A);
5905 AAExecutionDomainFunction *
AA =
nullptr;
5915 "AAExecutionDomain can only be created for function position!");
5917 AA =
new (
A.Allocator) AAExecutionDomainFunction(IRP,
A);
5924AAHeapToShared &AAHeapToShared::createForPosition(
const IRPosition &IRP,
5926 AAHeapToSharedFunction *
AA =
nullptr;
5936 "AAHeapToShared can only be created for function position!");
5938 AA =
new (
A.Allocator) AAHeapToSharedFunction(IRP,
A);
5945AAKernelInfo &AAKernelInfo::createForPosition(
const IRPosition &IRP,
5947 AAKernelInfo *AA =
nullptr;
5957 AA =
new (
A.Allocator) AAKernelInfoCallSite(IRP,
A);
5960 AA =
new (
A.Allocator) AAKernelInfoFunction(IRP,
A);
5967AAFoldRuntimeCall &AAFoldRuntimeCall::createForPosition(
const IRPosition &IRP,
5969 AAFoldRuntimeCall *AA =
nullptr;
5978 llvm_unreachable(
"KernelInfo can only be created for call site position!");
5980 AA =
new (
A.Allocator) AAFoldRuntimeCallCallSiteReturned(IRP,
A);
6000 unsigned NumAssumedCallees) {
6018 if (Kernels.contains(&
F))
6020 return !
F.use_empty();
6027 return ORA <<
"Could not internalize function. "
6028 <<
"Some optimizations may not be possible. [OMP140]";
6040 if (!
F.isDeclaration() && !Kernels.contains(&
F) && IsCalled(
F) &&
6044 }
else if (!
F.hasLocalLinkage() && !
F.hasFnAttribute(Attribute::Cold)) {
6057 if (!
F.isDeclaration() && !InternalizedMap.
lookup(&
F)) {
6059 Functions.insert(&
F);
6077 OMPInformationCache InfoCache(M, AG, Allocator,
nullptr, PostLink);
6079 unsigned MaxFixpointIterations =
6092 return F.hasFnAttribute(
"kernel");
6097 OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache,
A);
6103 if (!
F.isDeclaration() && !Kernels.contains(&
F) &&
6104 !
F.hasFnAttribute(Attribute::NoInline))
6105 F.addFnAttr(Attribute::AlwaysInline);
6135 Module &M = *
C.begin()->getFunction().getParent();
6157 OMPInformationCache InfoCache(*(Functions.back()->getParent()), AG, Allocator,
6158 &Functions, PostLink);
6160 unsigned MaxFixpointIterations =
6175 OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache,
A);
6176 bool Changed = OMPOpt.run(
false);
6195 if (
F.hasKernelCallingConv()) {
6200 ++NumOpenMPTargetRegionKernels;
6203 ++NumNonOpenMPTargetRegionKernels;
6210 Metadata *MD = M.getModuleFlag(
"openmp");
6218 Metadata *MD = M.getModuleFlag(
"openmp-device");
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
amdgpu aa AMDGPU Address space based Alias Analysis Wrapper
amdgpu next use AMDGPU Next Use Analysis Printer
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
static cl::opt< unsigned > SetFixpointIterations("attributor-max-iterations", cl::Hidden, cl::desc("Maximal number of fixpoint iterations."), cl::init(32))
static const Function * getParent(const Value *V)
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file provides interfaces used to manipulate a call graph, regardless if it is a "old style" Call...
This file provides interfaces used to build and manipulate a call graph, which is a very useful tool ...
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file defines the DenseSet and SmallDenseSet classes.
This file defines an array type that can be indexed using scoped enum values.
static void emitRemark(const Function &F, OptimizationRemarkEmitter &ORE, bool Skip)
Loop::LoopBounds::Direction Direction
Machine Check Debug Module
This file provides utility analysis objects describing memory locations.
uint64_t IntrinsicInst * II
This file defines constans and helpers used when dealing with OpenMP.
This file defines constans that will be used by both host and device compilation.
static constexpr auto TAG
static cl::opt< bool > HideMemoryTransferLatency("openmp-hide-memory-transfer-latency", cl::desc("[WIP] Tries to hide the latency of host to device memory" " transfers"), cl::Hidden, cl::init(false))
static cl::opt< bool > DisableOpenMPOptStateMachineRewrite("openmp-opt-disable-state-machine-rewrite", cl::desc("Disable OpenMP optimizations that replace the state machine."), cl::Hidden, cl::init(false))
static cl::opt< bool > EnableParallelRegionMerging("openmp-opt-enable-merging", cl::desc("Enable the OpenMP region merging optimization."), cl::Hidden, cl::init(false))
static cl::opt< bool > PrintModuleAfterOptimizations("openmp-opt-print-module-after", cl::desc("Print the current module after OpenMP optimizations."), cl::Hidden, cl::init(false))
#define KERNEL_ENVIRONMENT_CONFIGURATION_GETTER(MEMBER)
#define KERNEL_ENVIRONMENT_CONFIGURATION_IDX(MEMBER, IDX)
#define KERNEL_ENVIRONMENT_CONFIGURATION_SETTER(MEMBER)
static cl::opt< bool > PrintOpenMPKernels("openmp-print-gpu-kernels", cl::init(false), cl::Hidden)
static cl::opt< bool > DisableOpenMPOptFolding("openmp-opt-disable-folding", cl::desc("Disable OpenMP optimizations involving folding."), cl::Hidden, cl::init(false))
static bool shouldSpecializeIndirectCallee(Attributor &, const AbstractAttribute &, CallBase &, Function &, unsigned NumAssumedCallees)
Bound the if-cascade AAIndirectCallInfo builds for an indirect call.
static cl::opt< bool > PrintModuleBeforeOptimizations("openmp-opt-print-module-before", cl::desc("Print the current module before OpenMP optimizations."), cl::Hidden, cl::init(false))
static cl::opt< unsigned > SetFixpointIterations("openmp-opt-max-iterations", cl::Hidden, cl::desc("Maximal number of attributor iterations."), cl::init(256))
static cl::opt< bool > DisableInternalization("openmp-opt-disable-internalization", cl::desc("Disable function internalization."), cl::Hidden, cl::init(false))
static cl::opt< bool > PrintICVValues("openmp-print-icv-values", cl::init(false), cl::Hidden)
static cl::opt< bool > DisableOpenMPOptimizations("openmp-opt-disable", cl::desc("Disable OpenMP specific optimizations."), cl::Hidden, cl::init(false))
static cl::opt< unsigned > SharedMemoryLimit("openmp-opt-shared-limit", cl::Hidden, cl::desc("Maximum amount of shared memory to use."), cl::init(std::numeric_limits< unsigned >::max()))
static cl::opt< bool > EnableVerboseRemarks("openmp-opt-verbose-remarks", cl::desc("Enables more verbose remarks."), cl::Hidden, cl::init(false))
static cl::opt< unsigned > MaxCalleesForSpecialization("openmp-opt-max-callees-for-specialization", cl::Hidden, cl::desc("Number of possible callees above which an indirect call site is " "left alone rather than specialized into an if-cascade."), cl::init(3))
static cl::opt< bool > DisableOpenMPOptDeglobalization("openmp-opt-disable-deglobalization", cl::desc("Disable OpenMP optimizations involving deglobalization."), cl::Hidden, cl::init(false))
static cl::opt< bool > DisableOpenMPOptBarrierElimination("openmp-opt-disable-barrier-elimination", cl::desc("Disable OpenMP optimizations that eliminate barriers."), cl::Hidden, cl::init(false))
static cl::opt< bool > DeduceICVValues("openmp-deduce-icv-values", cl::init(false), cl::Hidden)
#define KERNEL_ENVIRONMENT_IDX(MEMBER, IDX)
#define KERNEL_ENVIRONMENT_GETTER(MEMBER, RETURNTYPE)
static cl::opt< bool > DisableOpenMPOptSPMDization("openmp-opt-disable-spmdization", cl::desc("Disable OpenMP optimizations involving SPMD-ization."), cl::Hidden, cl::init(false))
static cl::opt< bool > AlwaysInlineDeviceFunctions("openmp-opt-inline-device", cl::desc("Inline all applicable functions on the device."), cl::Hidden, cl::init(false))
FunctionAnalysisManager FAM
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
This file contains the declarations for profiling metadata utility functions.
static StringRef getName(Value *V)
Remove Loads Into Fake Uses
std::pair< BasicBlock *, BasicBlock * > Edge
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T, const llvm::StringTable &StandardNames, VectorLibrary VecLib)
Initialize the set of available library functions based on the specified target triple.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
iterator begin()
Instruction iterator methods.
LLVM_ABI const_iterator getFirstInsertionPt() const
Returns an iterator to the first instruction in this block that is suitable for inserting a non-PHI i...
LLVM_ABI BasicBlock * splitBasicBlock(iterator I, const Twine &BBName="")
Split the basic block into two basic blocks at the specified instruction.
const Function * getParent() const
Return the enclosing method, or null if none.
reverse_iterator rbegin()
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
LLVM_ABI const BasicBlock * getUniqueSuccessor() const
Return the successor of this block if it has a unique successor.
InstListType::reverse_iterator reverse_iterator
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
void setCallingConv(CallingConv::ID CC)
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
bool doesNotAccessMemory(unsigned OpNo) const
bool hasFnAttr(Attribute::AttrKind Kind) const
Determine whether this call has the given attribute.
LLVM_ABI bool isIndirectCall() const
Return true if the callsite is an indirect call.
bool isCallee(Value::const_user_iterator UI) const
Determine whether the passed iterator points to the callee operand's Use.
Value * getCalledOperand() const
Value * getArgOperand(unsigned i) const
void setArgOperand(unsigned i, Value *v)
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
unsigned getArgOperandNo(const Use *U) const
Given a use for a arg operand, get the arg operand number that corresponds to it.
unsigned arg_size() const
AttributeList getAttributes() const
Return the attributes for this call.
void addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind)
Adds the attribute to the indicated argument.
bool isArgOperand(const Use *U) const
bool hasOperandBundles() const
Return true if this User has any operand bundles.
LLVM_ABI Function * getCaller()
Helper to get the caller (the parent function).
Wrapper to unify "old style" CallGraph and "new style" LazyCallGraph.
void initialize(LazyCallGraph &LCG, LazyCallGraph::SCC &SCC, CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR)
Initializers for usage outside of a CGSCC pass, inside a CGSCC pass in the old and new pass manager (...
This class represents a function call, abstracting a target machine's calling convention.
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
@ ICMP_SLT
signed less than
static CondBrInst * Create(Value *Cond, BasicBlock *IfTrue, BasicBlock *IfFalse, InsertPosition InsertBefore=nullptr)
static LLVM_ABI Constant * getPointerCast(Constant *C, Type *Ty)
Create a BitCast, AddrSpaceCast, or a PtrToInt cast constant expression.
static LLVM_ABI Constant * getPointerBitCastOrAddrSpaceCast(Constant *C, Type *Ty)
Create a BitCast or AddrSpaceCast for a pointer type depending on the address space.
This is the shared class of boolean and integer constants.
IntegerType * getIntegerType() const
Variant of the getType() method to always return an IntegerType, which reduces the amount of casting ...
static LLVM_ABI ConstantInt * getTrue(LLVMContext &Context)
bool isZero() const
This is just a convenience method to make client code smaller for a common code.
int64_t getSExtValue() const
Return the constant as a 64-bit integer value after it has been sign extended as appropriate for the ...
static LLVM_ABI ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
This is an important base class in LLVM.
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
ValueT lookup(const_arg_type_t< KeyT > Val) const
Return the entry for the specified key, or a default constructed value if no such entry exists.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
LLVM_ABI Instruction * findNearestCommonDominator(Instruction *I1, Instruction *I2) const
Find the nearest instruction I that dominates both I1 and I2, in the sense that a result produced bef...
static ErrorSuccess success()
Create a success value.
SyncScope::ID getSyncScopeID() const
Returns the synchronization scope ID of this fence instruction.
AtomicOrdering getOrdering() const
Returns the ordering constraint of this fence instruction.
A proxy from a FunctionAnalysisManager to an SCC.
const BasicBlock & getEntryBlock() const
const BasicBlock & front() const
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
void setEntryCount(uint64_t Count, const DenseSet< GlobalValue::GUID > *Imports=nullptr)
Set the entry count for this function.
Argument * getArg(unsigned i) const
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
LLVM_ABI bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
bool hasLocalLinkage() const
Module * getParent()
Get the module that this global value is contained inside of...
@ PrivateLinkage
Like Internal, but omit from symbol table.
@ InternalLinkage
Rename collisions when linking (static functions).
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
LLVM_ABI void setInitializer(Constant *InitVal)
setInitializer - Sets the initializer for this global variable, removing any existing initializer if ...
CondBrInst * CreateCondBr(Value *Cond, BasicBlock *True, BasicBlock *False, MDNode *BranchWeights=nullptr, MDNode *Unpredictable=nullptr)
Create a conditional 'br Cond, TrueDest, FalseDest' instruction.
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)
Value * CreateIsNull(Value *Arg, const Twine &Name="")
Return a boolean value testing if Arg == 0.
LLVM_ABI bool isLifetimeStartOrEnd() const LLVM_READONLY
Return true if the instruction is a llvm.lifetime.start or llvm.lifetime.end marker.
LLVM_ABI bool mayWriteToMemory() const LLVM_READONLY
Return true if this instruction may modify memory.
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
LLVM_ABI bool mayHaveSideEffects() const LLVM_READONLY
Return true if the instruction may have side effects.
LLVM_ABI bool mayReadFromMemory() const LLVM_READONLY
Return true if this instruction may read memory.
iterator_range< user_iterator > users()
void setDebugLoc(DebugLoc Loc)
Set the debug location information for this instruction.
LLVM_ABI void setSuccessor(unsigned Idx, BasicBlock *BB)
Update the specified successor to point at the provided block.
LLVM_ABI std::optional< StringRef > getSyncScopeName(SyncScope::ID Id) const
getSyncScopeName - Returns the name of a SyncScope::ID registered with LLVMContext,...
LLVM_ABI const DiagnosticHandler * getDiagHandlerPtr() const
getDiagHandlerPtr - Returns const raw pointer of DiagnosticHandler set by setDiagnosticHandler.
A node in the call graph.
An SCC of the call graph.
A lazily constructed view of the call graph of a module.
const MDOperand & getOperand(unsigned I) const
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
unsigned getNumOperands() const
Return number of MDNode operands.
LLVM_ABI void eraseFromParent()
This method unlinks 'this' from the containing function and deletes it.
LLVM_ABI StringRef getName() const
Return the name of the corresponding LLVM basic block, or an empty string.
A Module instance is used to store all the information related to an LLVM module.
const Triple & getTargetTriple() const
Get the target triple which is a string describing the target host.
LLVM_ABI Constant * getOrCreateIdent(Constant *SrcLocStr, uint32_t SrcLocStrSize, omp::IdentFlag Flags=omp::IdentFlag(0), unsigned Reserve2Flags=0)
Return an ident_t* encoding the source location SrcLocStr and Flags.
LLVM_ABI FunctionCallee getOrCreateRuntimeFunction(Module &M, omp::RuntimeFunction FnID)
Return the function declaration for the runtime function with FnID.
static LLVM_ABI std::pair< int32_t, int32_t > readThreadBoundsForKernel(const Triple &T, Function &Kernel)
}
LLVM_ABI Constant * getOrCreateSrcLocStr(StringRef LocStr, uint32_t &SrcLocStrSize)
Return the (LLVM-IR) string describing the source location LocStr.
IRBuilder<>::InsertPoint InsertPointTy
Type used throughout for insertion points.
IRBuilder Builder
The LLVM-IR Builder used to create IR.
static LLVM_ABI std::pair< int32_t, int32_t > readTeamBoundsForKernel(const Triple &T, Function &Kernel)
Read/write a bounds on teams for Kernel.
bool updateToLocation(const LocationDescription &Loc)
Update the internal location to Loc.
LLVM_ABI PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG, CGSCCUpdateResult &UR)
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
static LLVM_ABI ProfileSummary * getFromMD(Metadata *MD)
Construct profile summary from metdata.
static ReturnInst * Create(LLVMContext &C, Value *retVal=nullptr, InsertPosition InsertBefore=nullptr)
A vector that has set insertion semantics.
size_type size() const
Determine the number of elements in the SetVector.
size_type count(const_arg_type key) const
Count the number of elements of a given key in the SetVector.
bool insert(const value_type &X)
Insert a new element into the SetVector.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
reference emplace_back(ArgTypes &&... Args)
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Triple - Helper class for working with autoconf configuration names.
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
LLVM_ABI unsigned getPointerAddressSpace() const
Get the address space of this pointer or pointer vector type.
static UncondBrInst * Create(BasicBlock *Target, InsertPosition InsertBefore=nullptr)
static LLVM_ABI UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
A Use represents the edge between a Value definition and its users.
LLVM_ABI bool replaceUsesOfWith(Value *From, Value *To)
Replace uses of one Value with another.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void setName(const Twine &Name)
Change the name of the value.
bool hasOneUse() const
Return true if there is exactly one use of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVMContext & getContext() const
All values hold a context through their type.
iterator_range< user_iterator > users()
LLVM_ABI const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
const ParentTy * getParent() const
self_iterator getIterator()
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
GlobalVariable * getKernelEnvironementGVFromKernelInitCB(CallBase *KernelInitCB)
ConstantStruct * getKernelEnvironementFromKernelInitCB(CallBase *KernelInitCB)
Abstract Attribute helper functions.
LLVM_ABI bool isValidAtPosition(const ValueAndContext &VAC, InformationCache &InfoCache)
Return true if the value of VAC is a valid at the position of VAC, that is a constant,...
LLVM_ABI bool isPotentiallyAffectedByBarrier(Attributor &A, const Instruction &I, const AbstractAttribute &QueryingAA)
Return true if I is potentially affected by a barrier.
LLVM_ABI bool isNoSyncInst(Attributor &A, const Instruction &I, const AbstractAttribute &QueryingAA)
Return true if I is a nosync instruction.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr E & operator^=(E &LHS, E RHS)
@ BasicBlock
Various leaf nodes.
@ SingleThread
Synchronized with respect to signal handlers executing in the same thread.
@ System
Synchronized with respect to all concurrently executing threads.
initializer< Ty > init(const Ty &Val)
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
constexpr uint64_t PointerSize
aarch64 pointer size.
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
LLVM_ABI bool isOpenMPDevice(Module &M)
Helper to determine if M is a OpenMP target offloading device module.
LLVM_ABI bool containsOpenMP(Module &M)
Helper to determine if M contains OpenMP.
InternalControlVar
IDs for all Internal Control Variables (ICVs).
RuntimeFunction
IDs for all omp runtime library (RTL) functions.
LLVM_ABI KernelSet getDeviceKernels(Module &M)
Get OpenMP device kernels in M.
@ OMP_TGT_EXEC_MODE_GENERIC_SPMD
@ OMP_TGT_EXEC_MODE_GENERIC
SetVector< Kernel > KernelSet
Set of kernels in the module.
Function * Kernel
Summary of a kernel (=entry point for target offloading).
LLVM_ABI bool isOpenMPKernel(Function &Fn)
Return true iff Fn is an OpenMP GPU kernel; Fn has the "kernel" attribute.
DiagnosticInfoOptimizationBase::Argument NV
NodeAddr< UseNode * > Use
friend class Instruction
Iterator for Instructions in a `BasicBlock.
LLVM_ABI iterator begin() const
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
bool succ_empty(const Instruction *I)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI bool isRemovableAlloc(const CallBase *V, const TargetLibraryInfo *TLI)
Return true if this is a call to an allocation function that does not have side effects that we are r...
bool operator!=(uint64_t V1, const APInt &V2)
constexpr from_range_t from_range
Value * GetPointerBaseWithConstantOffset(Value *Ptr, int64_t &Offset, const DataLayout &DL, bool AllowNonInbounds=true)
Analyze the specified pointer to see if it can be expressed as a base pointer plus a constant offset.
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
AnalysisManager< LazyCallGraph::SCC, LazyCallGraph & > CGSCCAnalysisManager
The CGSCC analysis manager.
@ ThinLTOPostLink
ThinLTO postlink (backend compile) phase.
@ FullLTOPostLink
Full LTO postlink (backend compile) phase.
@ ThinLTOPreLink
ThinLTO prelink (summary) phase.
auto dyn_cast_or_null(const Y &Val)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
std::optional< std::pair< AtomicScope, bool > > parseAtomicScopeIRString(const Triple &T, StringRef Name)
Parses a target syncscope string into its abstract scope, the inverse of getAtomicScopeIRString.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
LLVM_ABI const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=MaxLookupSearchDepth, bool MustPreserveProvenance=false)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
MutableArrayRef(T &OneElt) -> MutableArrayRef< T >
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
bool operator&=(SparseBitVector< ElementSize > *LHS, const SparseBitVector< ElementSize > &RHS)
LLVM_ABI BasicBlock * SplitBlock(BasicBlock *Old, BasicBlock::iterator SplitPt, DominatorTree *DT, LoopInfo *LI=nullptr, MemorySSAUpdater *MSSAU=nullptr, const Twine &BBName="")
Split the specified block at the specified instruction.
auto count(R &&Range, const E &Element)
Wrapper function around std::count to count the number of times an element Element occurs in the give...
ArrayRef(const T &OneElt) -> ArrayRef< T >
LLVM_ABI Value * getFreedOperand(const CallBase *CB, const TargetLibraryInfo *TLI)
If this if a call to a free function, return the freed operand.
std::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
auto predecessors(const MachineBasicBlock *BB)
LLVM_ABI Constant * ConstantFoldInsertValueInstruction(Constant *Agg, Constant *Val, ArrayRef< unsigned > Idxs)
Attempt to constant fold an insertvalue instruction with the specified operands and indices.
@ OPTIONAL
The target may be valid if the source is not.
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
BumpPtrAllocatorImpl<> BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
@ End
Run the machine verifier once, at the end of the pipeline.
LLVM_ABI void setFittedBranchWeights(Instruction &I, ArrayRef< uint64_t > Weights, bool IsExpected, bool ElideAllZero=false)
Variant of setBranchWeights where the Weights will be fit first to uint32_t by shifting right.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
static LLVM_ABI AAExecutionDomain & createForPosition(const IRPosition &IRP, Attributor &A)
Create an abstract attribute view for the position IRP.
AAExecutionDomain(const IRPosition &IRP, Attributor &A)
static LLVM_ABI const char ID
Unique ID (due to the unique address)
AccessKind
Simple enum to distinguish read/write/read-write accesses.
StateType::base_t MemoryLocationsKind
static LLVM_ABI bool isAlignedBarrier(const CallBase &CB, bool ExecutedAligned)
Helper function to determine if CB is an aligned (GPU) barrier.
Base struct for all "concrete attribute" deductions.
virtual const char * getIdAddr() const =0
This function should return the address of the ID of the AbstractAttribute.
An interface to query the internal state of an abstract attribute.
Wrapper for FunctionAnalysisManager.
Configuration for the Attributor.
std::function< void(Attributor &A, const Function &F)> InitializationCallback
Callback function to be invoked on internal functions marked live.
std::optional< unsigned > MaxFixpointIterations
Maximum number of iterations to run until fixpoint.
bool RewriteSignatures
Flag to determine if we rewrite function signatures.
OptimizationRemarkGetter OREGetter
IPOAmendableCBTy IPOAmendableCB
bool IsModulePass
Is the user of the Attributor a module pass or not.
std::function< bool(Attributor &A, const AbstractAttribute &AA, CallBase &CB, Function &AssumedCallee, unsigned NumAssumedCallees)> IndirectCalleeSpecializationCallback
Callback function to determine if an indirect call targets should be made direct call targets (with a...
bool DefaultInitializeLiveInternals
Flag to determine if we want to initialize all default AAs for an internal function marked live.
The fixpoint analysis framework that orchestrates the attribute deduction.
static LLVM_ABI bool isInternalizable(Function &F)
Returns true if the function F can be internalized.
std::function< std::optional< Value * >( const IRPosition &, const AbstractAttribute *, bool &)> SimplifictionCallbackTy
Register CB as a simplification callback.
std::function< std::optional< Constant * >( const GlobalVariable &, const AbstractAttribute *, bool &)> GlobalVariableSimplifictionCallbackTy
Register CB as a simplification callback.
std::function< bool(Attributor &, const AbstractAttribute *)> VirtualUseCallbackTy
static LLVM_ABI bool internalizeFunctions(SmallPtrSetImpl< Function * > &FnSet, DenseMap< Function *, Function * > &FnMap)
Make copies of each function in the set FnSet such that the copied version has internal linkage after...
Simple wrapper for a single bit (boolean) state.
Support structure for SCC passes to communicate updates the call graph back to the CGSCC pass manager...
bool isAnyRemarkEnabled(StringRef PassName) const
Return true if any type of remarks are enabled for this pass.
Helper to describe and deal with positions in the LLVM-IR.
static const IRPosition callsite_returned(const CallBase &CB)
Create a position describing the returned value of CB.
static const IRPosition returned(const Function &F, const CallBaseContext *CBContext=nullptr)
Create a position describing the returned value of F.
static const IRPosition value(const Value &V, const CallBaseContext *CBContext=nullptr)
Create a position describing the value of V.
static const IRPosition inst(const Instruction &I, const CallBaseContext *CBContext=nullptr)
Create a position describing the instruction I.
@ IRP_ARGUMENT
An attribute for a function argument.
@ IRP_RETURNED
An attribute for the function return value.
@ IRP_CALL_SITE
An attribute for a call site (function scope).
@ IRP_CALL_SITE_RETURNED
An attribute for a call site return value.
@ IRP_FUNCTION
An attribute for a function (scope).
@ IRP_FLOAT
A position that is not associated with a spot suitable for attributes.
@ IRP_CALL_SITE_ARGUMENT
An attribute for a call site argument.
@ IRP_INVALID
An invalid position.
static const IRPosition function(const Function &F, const CallBaseContext *CBContext=nullptr)
Create a position describing the function scope of F.
Kind getPositionKind() const
Return the associated position kind.
static const IRPosition callsite_function(const CallBase &CB)
Create a position describing the function scope of CB.
Defines various target-specific GPU grid values that must be consistent between host RTL (plugin),...