LLVM 24.0.0git
OpenMPOpt.cpp
Go to the documentation of this file.
1//===-- IPO/OpenMPOpt.cpp - Collection of OpenMP specific optimizations ---===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// OpenMP specific optimizations:
10//
11// - Deduplication of runtime calls, e.g., omp_get_thread_num.
12// - Replacing globalized device memory with stack memory.
13// - Replacing globalized device memory with shared memory.
14// - Parallel region merging.
15// - Transforming generic-mode device kernels to SPMD mode.
16// - Specializing the state machine for generic-mode device kernels.
17//
18//===----------------------------------------------------------------------===//
19
21
22#include "llvm/ADT/DenseSet.h"
25#include "llvm/ADT/SetVector.h"
28#include "llvm/ADT/Statistic.h"
30#include "llvm/ADT/StringRef.h"
39#include "llvm/IR/Assumptions.h"
40#include "llvm/IR/BasicBlock.h"
41#include "llvm/IR/Constants.h"
43#include "llvm/IR/Dominators.h"
44#include "llvm/IR/Function.h"
45#include "llvm/IR/GlobalValue.h"
47#include "llvm/IR/InstrTypes.h"
48#include "llvm/IR/Instruction.h"
51#include "llvm/IR/IntrinsicsAMDGPU.h"
52#include "llvm/IR/IntrinsicsNVPTX.h"
53#include "llvm/IR/LLVMContext.h"
54#include "llvm/IR/MDBuilder.h"
59#include "llvm/Support/Debug.h"
65
66#include <algorithm>
67#include <memory>
68#include <optional>
69#include <string>
70
71using namespace llvm;
72using namespace omp;
73
74#define DEBUG_TYPE "openmp-opt"
75
77 "openmp-opt-disable", cl::desc("Disable OpenMP specific optimizations."),
78 cl::Hidden, cl::init(false));
79
81 "openmp-opt-enable-merging",
82 cl::desc("Enable the OpenMP region merging optimization."), cl::Hidden,
83 cl::init(false));
84
85static cl::opt<bool>
86 DisableInternalization("openmp-opt-disable-internalization",
87 cl::desc("Disable function internalization."),
88 cl::Hidden, cl::init(false));
89
90static cl::opt<bool> DeduceICVValues("openmp-deduce-icv-values",
91 cl::init(false), cl::Hidden);
92static cl::opt<bool> PrintICVValues("openmp-print-icv-values", cl::init(false),
94static cl::opt<bool> PrintOpenMPKernels("openmp-print-gpu-kernels",
95 cl::init(false), cl::Hidden);
96
98 "openmp-hide-memory-transfer-latency",
99 cl::desc("[WIP] Tries to hide the latency of host to device memory"
100 " transfers"),
101 cl::Hidden, cl::init(false));
102
104 "openmp-opt-disable-deglobalization",
105 cl::desc("Disable OpenMP optimizations involving deglobalization."),
106 cl::Hidden, cl::init(false));
107
109 "openmp-opt-disable-spmdization",
110 cl::desc("Disable OpenMP optimizations involving SPMD-ization."),
111 cl::Hidden, cl::init(false));
112
114 "openmp-opt-disable-folding",
115 cl::desc("Disable OpenMP optimizations involving folding."), cl::Hidden,
116 cl::init(false));
117
119 "openmp-opt-disable-state-machine-rewrite",
120 cl::desc("Disable OpenMP optimizations that replace the state machine."),
121 cl::Hidden, cl::init(false));
122
124 "openmp-opt-disable-barrier-elimination",
125 cl::desc("Disable OpenMP optimizations that eliminate barriers."),
126 cl::Hidden, cl::init(false));
127
129 "openmp-opt-print-module-after",
130 cl::desc("Print the current module after OpenMP optimizations."),
131 cl::Hidden, cl::init(false));
132
134 "openmp-opt-print-module-before",
135 cl::desc("Print the current module before OpenMP optimizations."),
136 cl::Hidden, cl::init(false));
137
139 "openmp-opt-inline-device",
140 cl::desc("Inline all applicable functions on the device."), cl::Hidden,
141 cl::init(false));
142
143static cl::opt<bool>
144 EnableVerboseRemarks("openmp-opt-verbose-remarks",
145 cl::desc("Enables more verbose remarks."), cl::Hidden,
146 cl::init(false));
147
149 SetFixpointIterations("openmp-opt-max-iterations", cl::Hidden,
150 cl::desc("Maximal number of attributor iterations."),
151 cl::init(256));
152
154 SharedMemoryLimit("openmp-opt-shared-limit", cl::Hidden,
155 cl::desc("Maximum amount of shared memory to use."),
156 cl::init(std::numeric_limits<unsigned>::max()));
157
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."),
162 cl::init(3));
163
164STATISTIC(NumOpenMPRuntimeCallsDeduplicated,
165 "Number of OpenMP runtime calls deduplicated");
166STATISTIC(NumOpenMPParallelRegionsDeleted,
167 "Number of OpenMP parallel regions deleted");
168STATISTIC(NumOpenMPRuntimeFunctionsIdentified,
169 "Number of OpenMP runtime functions identified");
170STATISTIC(NumOpenMPRuntimeFunctionUsesIdentified,
171 "Number of OpenMP runtime function uses identified");
172STATISTIC(NumOpenMPTargetRegionKernels,
173 "Number of OpenMP target region entry points (=kernels) identified");
174STATISTIC(NumNonOpenMPTargetRegionKernels,
175 "Number of non-OpenMP target region kernels identified");
176STATISTIC(NumOpenMPTargetRegionKernelsSPMD,
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");
191STATISTIC(NumOpenMPParallelRegionsMerged,
192 "Number of OpenMP parallel regions merged");
193STATISTIC(NumBytesMovedToSharedMemory,
194 "Amount of memory pushed to shared memory");
195STATISTIC(NumBarriersEliminated, "Number of redundant barriers eliminated");
196
197#if !defined(NDEBUG)
198static constexpr auto TAG = "[" DEBUG_TYPE "]";
199#endif
200
201namespace KernelInfo {
202
203// struct ConfigurationEnvironmentTy {
204// uint8_t UseGenericStateMachine;
205// uint8_t MayUseNestedParallelism;
206// llvm::omp::OMPTgtExecModeFlags ExecMode;
207// int32_t MinThreads;
208// int32_t MaxThreads;
209// int32_t MinTeams;
210// int32_t MaxTeams;
211// };
212
213// struct DynamicEnvironmentTy {
214// uint16_t DebugIndentionLevel;
215// };
216
217// struct KernelEnvironmentTy {
218// ConfigurationEnvironmentTy Configuration;
219// IdentTy *Ident;
220// DynamicEnvironmentTy *DynamicEnv;
221// };
222
223#define KERNEL_ENVIRONMENT_IDX(MEMBER, IDX) \
224 constexpr unsigned MEMBER##Idx = IDX;
225
226KERNEL_ENVIRONMENT_IDX(Configuration, 0)
228
229#undef KERNEL_ENVIRONMENT_IDX
230
231#define KERNEL_ENVIRONMENT_CONFIGURATION_IDX(MEMBER, IDX) \
232 constexpr unsigned MEMBER##Idx = IDX;
233
234KERNEL_ENVIRONMENT_CONFIGURATION_IDX(UseGenericStateMachine, 0)
235KERNEL_ENVIRONMENT_CONFIGURATION_IDX(MayUseNestedParallelism, 1)
241
242#undef KERNEL_ENVIRONMENT_CONFIGURATION_IDX
243
244#define KERNEL_ENVIRONMENT_GETTER(MEMBER, RETURNTYPE) \
245 RETURNTYPE *get##MEMBER##FromKernelEnvironment(ConstantStruct *KernelEnvC) { \
246 return cast<RETURNTYPE>(KernelEnvC->getAggregateElement(MEMBER##Idx)); \
247 }
248
251
252#undef KERNEL_ENVIRONMENT_GETTER
253
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)); \
260 }
261
262KERNEL_ENVIRONMENT_CONFIGURATION_GETTER(UseGenericStateMachine)
263KERNEL_ENVIRONMENT_CONFIGURATION_GETTER(MayUseNestedParallelism)
269
270#undef KERNEL_ENVIRONMENT_CONFIGURATION_GETTER
271
274 constexpr int InitKernelEnvironmentArgNo = 0;
276 KernelInitCB->getArgOperand(InitKernelEnvironmentArgNo)
278}
279
285} // namespace KernelInfo
286
287namespace {
288
289struct AAHeapToShared;
290
291struct AAICVTracker;
292
293/// OpenMP specific information. For now, stores RFIs and ICVs also needed for
294/// Attributor runs.
295struct OMPInformationCache : public InformationCache {
296 OMPInformationCache(Module &M, AnalysisGetter &AG,
297 BumpPtrAllocator &Allocator, SetVector<Function *> *CGSCC,
298 bool OpenMPPostLink)
299 : InformationCache(M, AG, Allocator, CGSCC), OMPBuilder(M),
300 OpenMPPostLink(OpenMPPostLink) {
301
302 OMPBuilder.Config.IsTargetDevice = isOpenMPDevice(OMPBuilder.M);
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;
311 break;
312 default:
313 OMPBuilder.Config.IsGPU = false;
314 break;
315 }
316 OMPBuilder.initialize();
317 initializeRuntimeFunctions(M);
318 initializeInternalControlVars();
319 }
320
321 /// Generic information that describes an internal control variable.
322 struct InternalControlVarInfo {
323 /// The kind, as described by InternalControlVar enum.
325
326 /// The name of the ICV.
327 StringRef Name;
328
329 /// Environment variable associated with this ICV.
330 StringRef EnvVarName;
331
332 /// Initial value kind.
333 ICVInitValue InitKind;
334
335 /// Initial value.
336 ConstantInt *InitValue;
337
338 /// Setter RTL function associated with this ICV.
339 RuntimeFunction Setter;
340
341 /// Getter RTL function associated with this ICV.
342 RuntimeFunction Getter;
343
344 /// RTL Function corresponding to the override clause of this ICV
345 RuntimeFunction Clause;
346 };
347
348 /// Generic information that describes a runtime function
349 struct RuntimeFunctionInfo {
350
351 /// The kind, as described by the RuntimeFunction enum.
352 RuntimeFunction Kind;
353
354 /// The name of the function.
355 StringRef Name;
356
357 /// Flag to indicate a variadic function.
358 bool IsVarArg;
359
360 /// The return type of the function.
361 Type *ReturnType;
362
363 /// The argument types of the function.
364 SmallVector<Type *, 8> ArgumentTypes;
365
366 /// The declaration if available.
367 Function *Declaration = nullptr;
368
369 /// Uses of this runtime function per function containing the use.
370 using UseVector = SmallVector<Use *, 16>;
371
372 /// Clear UsesMap for runtime function.
373 void clearUsesMap() { UsesMap.clear(); }
374
375 /// Boolean conversion that is true if the runtime function was found.
376 operator bool() const { return Declaration; }
377
378 /// Return the vector of uses in function \p F.
379 UseVector &getOrCreateUseVector(Function *F) {
380 std::shared_ptr<UseVector> &UV = UsesMap[F];
381 if (!UV)
382 UV = std::make_shared<UseVector>();
383 return *UV;
384 }
385
386 /// Return the vector of uses in function \p F or `nullptr` if there are
387 /// none.
388 const UseVector *getUseVector(Function &F) const {
389 auto I = UsesMap.find(&F);
390 if (I != UsesMap.end())
391 return I->second.get();
392 return nullptr;
393 }
394
395 /// Return how many functions contain uses of this runtime function.
396 size_t getNumFunctionsWithUses() const { return UsesMap.size(); }
397
398 /// Return the number of arguments (or the minimal number for variadic
399 /// functions).
400 size_t getNumArgs() const { return ArgumentTypes.size(); }
401
402 /// Run the callback \p CB on each use and forget the use if the result is
403 /// true. The callback will be fed the function in which the use was
404 /// encountered as second argument.
405 void foreachUse(SmallVectorImpl<Function *> &SCC,
406 function_ref<bool(Use &, Function &)> CB) {
407 for (Function *F : SCC)
408 foreachUse(CB, F);
409 }
410
411 /// Run the callback \p CB on each use within the function \p F and forget
412 /// the use if the result is true.
413 void foreachUse(function_ref<bool(Use &, Function &)> CB, Function *F) {
414 SmallVector<unsigned, 8> ToBeDeleted;
415 ToBeDeleted.clear();
416
417 unsigned Idx = 0;
418 UseVector &UV = getOrCreateUseVector(F);
419
420 for (Use *U : UV) {
421 if (CB(*U, *F))
422 ToBeDeleted.push_back(Idx);
423 ++Idx;
424 }
425
426 // Remove the to-be-deleted indices in reverse order as prior
427 // modifications will not modify the smaller indices.
428 while (!ToBeDeleted.empty()) {
429 unsigned Idx = ToBeDeleted.pop_back_val();
430 UV[Idx] = UV.back();
431 UV.pop_back();
432 }
433 }
434
435 private:
436 /// Map from functions to all uses of this runtime function contained in
437 /// them.
438 DenseMap<Function *, std::shared_ptr<UseVector>> UsesMap;
439
440 public:
441 /// Iterators for the uses of this runtime function.
442 decltype(UsesMap)::iterator begin() { return UsesMap.begin(); }
443 decltype(UsesMap)::iterator end() { return UsesMap.end(); }
444 };
445
446 /// An OpenMP-IR-Builder instance
447 OpenMPIRBuilder OMPBuilder;
448
449 /// Map from runtime function kind to the runtime function description.
450 EnumeratedArray<RuntimeFunctionInfo, RuntimeFunction,
451 RuntimeFunction::OMPRTL___last>
452 RFIs;
453
454 /// Map from function declarations/definitions to their runtime enum type.
455 DenseMap<Function *, RuntimeFunction> RuntimeFunctionIDMap;
456
457 /// Map from ICV kind to the ICV description.
458 EnumeratedArray<InternalControlVarInfo, InternalControlVar,
459 InternalControlVar::ICV___last>
460 ICVs;
461
462 /// Helper to initialize all internal control variable information for those
463 /// defined in OMPKinds.def.
464 void initializeInternalControlVars() {
465#define ICV_RT_SET(_Name, RTL) \
466 { \
467 auto &ICV = ICVs[_Name]; \
468 ICV.Setter = RTL; \
469 }
470#define ICV_RT_GET(Name, RTL) \
471 { \
472 auto &ICV = ICVs[Name]; \
473 ICV.Getter = RTL; \
474 }
475#define ICV_DATA_ENV(Enum, _Name, _EnvVarName, Init) \
476 { \
477 auto &ICV = ICVs[Enum]; \
478 ICV.Name = _Name; \
479 ICV.Kind = Enum; \
480 ICV.InitKind = Init; \
481 ICV.EnvVarName = _EnvVarName; \
482 switch (ICV.InitKind) { \
483 case ICV_IMPLEMENTATION_DEFINED: \
484 ICV.InitValue = nullptr; \
485 break; \
486 case ICV_ZERO: \
487 ICV.InitValue = ConstantInt::get( \
488 Type::getInt32Ty(OMPBuilder.Int32->getContext()), 0); \
489 break; \
490 case ICV_FALSE: \
491 ICV.InitValue = ConstantInt::getFalse(OMPBuilder.Int1->getContext()); \
492 break; \
493 case ICV_LAST: \
494 break; \
495 } \
496 }
497#include "llvm/Frontend/OpenMP/OMPKinds.def"
498 }
499
500 /// Returns true if the function declaration \p F matches the runtime
501 /// function types, that is, return type \p RTFRetType, and argument types
502 /// \p RTFArgTypes.
503 static bool declMatchesRTFTypes(Function *F, Type *RTFRetType,
504 SmallVector<Type *, 8> &RTFArgTypes) {
505 // TODO: We should output information to the user (under debug output
506 // and via remarks).
507
508 if (!F)
509 return false;
510 if (F->getReturnType() != RTFRetType)
511 return false;
512 if (F->arg_size() != RTFArgTypes.size())
513 return false;
514
515 auto *RTFTyIt = RTFArgTypes.begin();
516 for (Argument &Arg : F->args()) {
517 if (Arg.getType() != *RTFTyIt)
518 return false;
519
520 ++RTFTyIt;
521 }
522
523 return true;
524 }
525
526 // Helper to collect all uses of the declaration in the UsesMap.
527 unsigned collectUses(RuntimeFunctionInfo &RFI, bool CollectStats = true) {
528 unsigned NumUses = 0;
529 if (!RFI.Declaration)
530 return NumUses;
531 OMPBuilder.addAttributes(RFI.Kind, *RFI.Declaration);
532
533 if (CollectStats) {
534 NumOpenMPRuntimeFunctionsIdentified += 1;
535 NumOpenMPRuntimeFunctionUsesIdentified += RFI.Declaration->getNumUses();
536 }
537
538 // TODO: We directly convert uses into proper calls and unknown uses.
539 for (Use &U : RFI.Declaration->uses()) {
540 if (Instruction *UserI = dyn_cast<Instruction>(U.getUser())) {
541 if (!CGSCC || CGSCC->empty() || CGSCC->contains(UserI->getFunction())) {
542 RFI.getOrCreateUseVector(UserI->getFunction()).push_back(&U);
543 ++NumUses;
544 }
545 } else {
546 RFI.getOrCreateUseVector(nullptr).push_back(&U);
547 ++NumUses;
548 }
549 }
550 return NumUses;
551 }
552
553 // Helper function to recollect uses of a runtime function.
554 void recollectUsesForFunction(RuntimeFunction RTF) {
555 auto &RFI = RFIs[RTF];
556 RFI.clearUsesMap();
557 collectUses(RFI, /*CollectStats*/ false);
558 }
559
560 /// Attach !callback metadata to a runtime function that takes one, so that
561 /// the Attributor sees the edge from the runtime call to the callback and
562 /// AAKernelInfo can look inside it. The runtime declares these functions
563 /// without the metadata, so OpenMPOpt supplies it from the table in
564 /// OMPKinds.def.
565 void setCallbackMetadata(Function *F, unsigned ArgNo, ArrayRef<int> Indices,
566 bool IsVarArg) {
567 if (!F || F->hasMetadata(LLVMContext::MD_callback))
568 return;
569
570 LLVMContext &Ctx = F->getContext();
571 MDBuilder MDB(Ctx);
572 F->addMetadata(LLVMContext::MD_callback,
573 *MDNode::get(Ctx, {MDB.createCallbackEncoding(ArgNo, Indices,
574 IsVarArg)}));
575 }
576
577 /// The callback a runtime function was handed, if it is one we can analyze.
578 /// Returns null when the call takes no callback, or when the callback is not
579 /// a definition this module can see, in which case its contents are unknown
580 /// and callers have to stay conservative.
581 static Function *getAnalyzableCallback(const CallBase &CB) {
583 if (!Callee)
584 return nullptr;
585 MDNode *CallbackMD = Callee->getMetadata(LLVMContext::MD_callback);
586 if (!CallbackMD || CallbackMD->getNumOperands() == 0)
587 return nullptr;
588 // TODO: A runtime function with more than one callback would need each of
589 // them checked; none of the ones in the table have more than one.
590 auto *Encoding = dyn_cast<MDNode>(CallbackMD->getOperand(0));
591 if (!Encoding || Encoding->getNumOperands() == 0)
592 return nullptr;
593 auto *ArgNoMD = dyn_cast<ConstantAsMetadata>(Encoding->getOperand(0));
594 if (!ArgNoMD)
595 return nullptr;
596 uint64_t ArgNo =
597 cast<ConstantInt>(ArgNoMD->getValue())->getLimitedValue(UINT64_MAX);
598 if (ArgNo >= CB.arg_size())
599 return nullptr;
600 auto *Callback =
602 if (!Callback || Callback->isDeclaration())
603 return nullptr;
604 return Callback;
605 }
606
607 // Helper function to recollect uses of all runtime functions.
608 void recollectUses() {
609 for (int Idx = 0; Idx < RFIs.size(); ++Idx)
610 recollectUsesForFunction(static_cast<RuntimeFunction>(Idx));
611 }
612
613 // Helper function to inherit the calling convention of the function callee.
614 void setCallingConvention(FunctionCallee Callee, CallInst *CI) {
615 if (Function *Fn = dyn_cast<Function>(Callee.getCallee()))
616 CI->setCallingConv(Fn->getCallingConv());
617 }
618
619 // Helper function to determine if it's legal to create a call to the runtime
620 // functions.
621 bool runtimeFnsAvailable(ArrayRef<RuntimeFunction> Fns) {
622 // We can always emit calls if we haven't yet linked in the runtime.
623 if (!OpenMPPostLink)
624 return true;
625
626 // Once the runtime has been already been linked in we cannot emit calls to
627 // any undefined functions.
628 for (RuntimeFunction Fn : Fns) {
629 RuntimeFunctionInfo &RFI = RFIs[Fn];
630
631 if (!RFI.Declaration || RFI.Declaration->isDeclaration())
632 return false;
633 }
634 return true;
635 }
636
637 /// Helper to initialize all runtime function information for those defined
638 /// in OpenMPKinds.def.
639 void initializeRuntimeFunctions(Module &M) {
640
641 // Helper macros for handling __VA_ARGS__ in OMP_RTL
642#define OMP_TYPE(VarName, ...) \
643 Type *VarName = OMPBuilder.VarName; \
644 (void)VarName;
645
646#define OMP_ARRAY_TYPE(VarName, ...) \
647 ArrayType *VarName##Ty = OMPBuilder.VarName##Ty; \
648 (void)VarName##Ty; \
649 PointerType *VarName##PtrTy = OMPBuilder.VarName##PtrTy; \
650 (void)VarName##PtrTy;
651
652#define OMP_FUNCTION_TYPE(VarName, ...) \
653 FunctionType *VarName = OMPBuilder.VarName; \
654 (void)VarName; \
655 PointerType *VarName##Ptr = OMPBuilder.VarName##Ptr; \
656 (void)VarName##Ptr;
657
658#define OMP_STRUCT_TYPE(VarName, ...) \
659 StructType *VarName = OMPBuilder.VarName; \
660 (void)VarName; \
661 PointerType *VarName##Ptr = OMPBuilder.VarName##Ptr; \
662 (void)VarName##Ptr;
663
664#define OMP_RTL(_Enum, _Name, _IsVarArg, _ReturnType, ...) \
665 { \
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]; \
672 RFI.Kind = _Enum; \
673 RFI.Name = _Name; \
674 RFI.IsVarArg = _IsVarArg; \
675 RFI.ReturnType = OMPBuilder._ReturnType; \
676 RFI.ArgumentTypes = std::move(ArgsTypes); \
677 RFI.Declaration = F; \
678 unsigned NumUses = collectUses(RFI); \
679 (void)NumUses; \
680 LLVM_DEBUG({ \
681 dbgs() << TAG << RFI.Name << (RFI.Declaration ? "" : " not") \
682 << " found\n"; \
683 if (RFI.Declaration) \
684 dbgs() << TAG << "-> got " << NumUses << " uses in " \
685 << RFI.getNumFunctionsWithUses() \
686 << " different functions.\n"; \
687 }); \
688 } \
689 }
690
691#define OMP_RTL_CB_INFO(_Enum, _Name, _ArgNo, _ArgIndices, _IsVarArg) \
692 setCallbackMetadata(M.getFunction(_Name), _ArgNo, _ArgIndices, _IsVarArg);
693
694#include "llvm/Frontend/OpenMP/OMPKinds.def"
695
696 // Remove the `noinline` attribute from `__kmpc`, `ompx::` and `omp_`
697 // functions, except if `optnone` is present.
698 if (isOpenMPDevice(M)) {
699 for (Function &F : M) {
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);
705 }
706 }
707
708 // TODO: We should attach the attributes defined in OMPKinds.def.
709 }
710
711 /// Collection of known OpenMP runtime functions..
712 DenseSet<const Function *> RTLFunctions;
713
714 /// Indicates if we have already linked in the OpenMP device library.
715 bool OpenMPPostLink = false;
716
717 /// Kernels that OpenMPOpt transformed from generic to SPMD mode. Recorded at
718 /// the transform (changeToSPMDMode) so later cleanup does not have to
719 /// re-derive the mode. Such kernels no longer run a generic-mode state
720 /// machine, so the parallel data-sharing wrapper passed to __kmpc_parallel_60
721 /// is dead in them.
722 SmallPtrSet<Function *, 8> SPMDizedKernels;
723};
724
725template <typename Ty, bool InsertInvalidates = true>
726struct BooleanStateWithSetVector : public BooleanState {
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);
732 }
733
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;
737 }
738 bool operator!=(const BooleanStateWithSetVector &RHS) const {
739 return !(*this == RHS);
740 }
741
742 bool empty() const { return Set.empty(); }
743 size_t size() const { return Set.size(); }
744
745 /// "Clamp" this state with \p RHS.
746 BooleanStateWithSetVector &operator^=(const BooleanStateWithSetVector &RHS) {
747 BooleanState::operator^=(RHS);
748 Set.insert_range(RHS.Set);
749 return *this;
750 }
751
752private:
753 /// A set to keep track of elements.
754 SetVector<Ty> Set;
755
756public:
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(); }
761};
762
763template <typename Ty, bool InsertInvalidates = true>
764using BooleanStateWithPtrSetVector =
765 BooleanStateWithSetVector<Ty *, InsertInvalidates>;
766
767struct KernelInfoState : AbstractState {
768 /// Flag to track if we reached a fixpoint.
769 bool IsAtFixpoint = false;
770
771 /// The parallel regions (identified by the outlined parallel functions) that
772 /// can be reached from the associated function.
773 BooleanStateWithPtrSetVector<CallBase, /* InsertInvalidates */ false>
774 ReachedKnownParallelRegions;
775
776 /// State to track what parallel region we might reach.
777 BooleanStateWithPtrSetVector<CallBase> ReachedUnknownParallelRegions;
778
779 /// State to track if we are in SPMD-mode, assumed or know, and why we decided
780 /// we cannot be. If it is assumed, then RequiresFullRuntime should also be
781 /// false.
782 BooleanStateWithPtrSetVector<Instruction, false> SPMDCompatibilityTracker;
783
784 /// The __kmpc_target_init call in this kernel, if any. If we find more than
785 /// one we abort as the kernel is malformed.
786 CallBase *KernelInitCB = nullptr;
787
788 /// The constant kernel environement as taken from and passed to
789 /// __kmpc_target_init.
790 ConstantStruct *KernelEnvC = nullptr;
791
792 /// The __kmpc_target_deinit call in this kernel, if any. If we find more than
793 /// one we abort as the kernel is malformed.
794 CallBase *KernelDeinitCB = nullptr;
795
796 /// Flag to indicate if the associated function is a kernel entry.
797 bool IsKernelEntry = false;
798
799 /// State to track what kernel entries can reach the associated function.
800 BooleanStateWithPtrSetVector<Function, false> ReachingKernelEntries;
801
802 /// State to indicate if we can track parallel level of the associated
803 /// function. We will give up tracking if we encounter unknown caller or the
804 /// caller is __kmpc_parallel_60.
805 BooleanStateWithSetVector<uint8_t> ParallelLevels;
806
807 /// Flag that indicates if the kernel has nested Parallelism
808 bool NestedParallelism = false;
809
810 /// Abstract State interface
811 ///{
812
813 KernelInfoState() = default;
814 KernelInfoState(bool BestState) {
815 if (!BestState)
816 indicatePessimisticFixpoint();
817 }
818
819 bool isValidState() const override { return true; }
820
821 bool isAtFixpoint() const override { return IsAtFixpoint; }
822
823 ChangeStatus indicatePessimisticFixpoint() override {
824 IsAtFixpoint = true;
825 ParallelLevels.indicatePessimisticFixpoint();
826 ReachingKernelEntries.indicatePessimisticFixpoint();
827 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
828 ReachedKnownParallelRegions.indicatePessimisticFixpoint();
829 ReachedUnknownParallelRegions.indicatePessimisticFixpoint();
830 NestedParallelism = true;
831 return ChangeStatus::CHANGED;
832 }
833
834 ChangeStatus indicateOptimisticFixpoint() override {
835 IsAtFixpoint = true;
836 ParallelLevels.indicateOptimisticFixpoint();
837 ReachingKernelEntries.indicateOptimisticFixpoint();
838 SPMDCompatibilityTracker.indicateOptimisticFixpoint();
839 ReachedKnownParallelRegions.indicateOptimisticFixpoint();
840 ReachedUnknownParallelRegions.indicateOptimisticFixpoint();
841 return ChangeStatus::UNCHANGED;
842 }
843
844 /// Return the assumed state
845 KernelInfoState &getAssumed() { return *this; }
846 const KernelInfoState &getAssumed() const { return *this; }
847
848 bool operator==(const KernelInfoState &RHS) const {
849 if (SPMDCompatibilityTracker != RHS.SPMDCompatibilityTracker)
850 return false;
851 if (ReachedKnownParallelRegions != RHS.ReachedKnownParallelRegions)
852 return false;
853 if (ReachedUnknownParallelRegions != RHS.ReachedUnknownParallelRegions)
854 return false;
855 if (ReachingKernelEntries != RHS.ReachingKernelEntries)
856 return false;
857 if (ParallelLevels != RHS.ParallelLevels)
858 return false;
859 if (NestedParallelism != RHS.NestedParallelism)
860 return false;
861 return true;
862 }
863
864 /// Returns true if this kernel contains any OpenMP parallel regions.
865 bool mayContainParallelRegion() {
866 return !ReachedKnownParallelRegions.empty() ||
867 !ReachedUnknownParallelRegions.empty();
868 }
869
870 /// Return empty set as the best state of potential values.
871 static KernelInfoState getBestState() { return KernelInfoState(true); }
872
873 static KernelInfoState getBestState(KernelInfoState &KIS) {
874 return getBestState();
875 }
876
877 /// Return full set as the worst state of potential values.
878 static KernelInfoState getWorstState() { return KernelInfoState(false); }
879
880 /// "Clamp" this state with \p KIS.
881 KernelInfoState operator^=(const KernelInfoState &KIS) {
882 // Do not merge two different _init and _deinit call sites.
883 if (KIS.KernelInitCB) {
884 if (KernelInitCB && KernelInitCB != KIS.KernelInitCB)
885 llvm_unreachable("Kernel that calls another kernel violates OpenMP-Opt "
886 "assumptions.");
887 KernelInitCB = KIS.KernelInitCB;
888 }
889 if (KIS.KernelDeinitCB) {
890 if (KernelDeinitCB && KernelDeinitCB != KIS.KernelDeinitCB)
891 llvm_unreachable("Kernel that calls another kernel violates OpenMP-Opt "
892 "assumptions.");
893 KernelDeinitCB = KIS.KernelDeinitCB;
894 }
895 if (KIS.KernelEnvC) {
896 if (KernelEnvC && KernelEnvC != KIS.KernelEnvC)
897 llvm_unreachable("Kernel that calls another kernel violates OpenMP-Opt "
898 "assumptions.");
899 KernelEnvC = KIS.KernelEnvC;
900 }
901 SPMDCompatibilityTracker ^= KIS.SPMDCompatibilityTracker;
902 ReachedKnownParallelRegions ^= KIS.ReachedKnownParallelRegions;
903 ReachedUnknownParallelRegions ^= KIS.ReachedUnknownParallelRegions;
904 NestedParallelism |= KIS.NestedParallelism;
905 return *this;
906 }
907
908 KernelInfoState operator&=(const KernelInfoState &KIS) {
909 return (*this ^= KIS);
910 }
911
912 ///}
913};
914
915/// Used to map the values physically (in the IR) stored in an offload
916/// array, to a vector in memory.
917struct OffloadArray {
918 /// Physical array (in the IR).
919 AllocaInst *Array = nullptr;
920 /// Mapped values.
921 SmallVector<Value *, 8> StoredValues;
922 /// Last stores made in the offload array.
923 SmallVector<StoreInst *, 8> LastAccesses;
924
925 OffloadArray() = default;
926
927 /// Initializes the OffloadArray with the values stored in \p Array before
928 /// instruction \p Before is reached. Returns false if the initialization
929 /// fails.
930 /// This MUST be used immediately after the construction of the object.
931 bool initialize(AllocaInst &Array, Instruction &Before) {
932 if (!getValues(Array, Before))
933 return false;
934
935 this->Array = &Array;
936 return true;
937 }
938
939 static const unsigned DeviceIDArgNum = 1;
940 static const unsigned BasePtrsArgNum = 3;
941 static const unsigned PtrsArgNum = 4;
942 static const unsigned SizesArgNum = 5;
943
944private:
945 /// Traverses the BasicBlock where \p Array is, collecting the stores made to
946 /// \p Array, leaving StoredValues with the values stored before the
947 /// instruction \p Before is reached.
948 bool getValues(AllocaInst &Array, Instruction &Before) {
949 // Initialize containers.
950 const DataLayout &DL = Array.getDataLayout();
951 std::optional<TypeSize> ArraySize = Array.getAllocationSize(DL);
952 if (!ArraySize || !ArraySize->isFixed())
953 return false;
954 const unsigned int PointerSize = DL.getPointerSize();
955 const uint64_t NumValues = ArraySize->getFixedValue() / PointerSize;
956 StoredValues.assign(NumValues, nullptr);
957 LastAccesses.assign(NumValues, nullptr);
958
959 // TODO: This assumes the instruction \p Before is in the same
960 // BasicBlock as Array. Make it general, for any control flow graph.
961 BasicBlock *BB = Array.getParent();
962 if (BB != Before.getParent())
963 return false;
964
965 for (Instruction &I : *BB) {
966 if (&I == &Before)
967 break;
968
969 if (!isa<StoreInst>(&I))
970 continue;
971
972 auto *S = cast<StoreInst>(&I);
973 int64_t Offset = -1;
974 auto *Dst =
975 GetPointerBaseWithConstantOffset(S->getPointerOperand(), Offset, DL);
976 if (Dst == &Array) {
977 int64_t Idx = Offset / PointerSize;
978 // Ignore updates that must be UB (probably in dead code at runtime)
979 if ((uint64_t)Idx < NumValues) {
980 StoredValues[Idx] = getUnderlyingObject(S->getValueOperand());
981 LastAccesses[Idx] = S;
982 }
983 }
984 }
985
986 return isFilled();
987 }
988
989 /// Returns true if all values in StoredValues and
990 /// LastAccesses are not nullptrs.
991 bool isFilled() {
992 const unsigned NumValues = StoredValues.size();
993 for (unsigned I = 0; I < NumValues; ++I) {
994 if (!StoredValues[I] || !LastAccesses[I])
995 return false;
996 }
997
998 return true;
999 }
1000};
1001
1002// Use the max outlined entry count. Instrumentation counts should already
1003// match across merged callbacks, but sample profiles can differ. Returns
1004// nullopt when no callback entry count is available.
1005static std::optional<uint64_t>
1006getMergedWrapperEntryCount(ArrayRef<CallInst *> ForkCalls,
1007 unsigned CallbackOpNo) {
1008 std::optional<uint64_t> EntryCount;
1009 for (CallInst *CI : ForkCalls) {
1011 CI->getArgOperand(CallbackOpNo)->stripPointerCasts());
1012 if (!Callback)
1013 continue;
1014 if (std::optional<uint64_t> EC = Callback->getEntryCount())
1015 // Each callback runs once per wrapper entry, so the counts should match.
1016 // The Sample profiles can disagree slightly, so take the largest.
1017 EntryCount = EntryCount ? std::max(*EntryCount, *EC) : *EC;
1018 }
1019 return EntryCount;
1020}
1021
1022static bool moduleHasSampleProfile(const Module &M) {
1023 std::unique_ptr<ProfileSummary> Summary(
1024 ProfileSummary::getFromMD(M.getProfileSummary(/*IsCS=*/false)));
1025 return Summary && Summary->getKind() == ProfileSummary::PSK_Sample;
1026}
1027
1028struct OpenMPOpt {
1029
1030 using OptimizationRemarkGetter =
1031 function_ref<OptimizationRemarkEmitter &(Function *)>;
1032
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) {}
1038
1039 /// Check if any remarks are enabled for openmp-opt
1040 bool remarksEnabled() {
1041 auto &Ctx = M.getContext();
1043 }
1044
1045 /// Run all OpenMP optimizations on the underlying SCC.
1046 bool run(bool IsModulePass) {
1047 if (SCC.empty())
1048 return false;
1049
1050 bool Changed = false;
1051
1052 LLVM_DEBUG(dbgs() << TAG << "Run on SCC with " << SCC.size()
1053 << " functions\n");
1054
1055 if (IsModulePass) {
1056 Changed |= runAttributor(IsModulePass);
1057
1058 // Recollect uses, in case Attributor deleted any.
1059 OMPInfoCache.recollectUses();
1060
1061 // TODO: This should be folded into buildCustomStateMachine.
1062 Changed |= rewriteDeviceCodeStateMachine();
1063
1064 // Drop the parallel data-sharing wrapper from __kmpc_parallel_60 calls in
1065 // SPMD kernels, where the runtime never uses it, so the (otherwise dead)
1066 // wrapper can be eliminated instead of lingering as a non-kernel LDS
1067 // user.
1068 Changed |= removeSPMDParallelWrappers();
1069
1070 if (remarksEnabled())
1071 analysisGlobalization();
1072 } else {
1073 if (PrintICVValues)
1074 printICVs();
1076 printKernels();
1077
1078 Changed |= runAttributor(IsModulePass);
1079
1080 // Recollect uses, in case Attributor deleted any.
1081 OMPInfoCache.recollectUses();
1082
1083 Changed |= deleteParallelRegions();
1084
1086 Changed |= hideMemTransfersLatency();
1087 Changed |= deduplicateRuntimeCalls();
1089 if (mergeParallelRegions()) {
1090 deduplicateRuntimeCalls();
1091 Changed = true;
1092 }
1093 }
1094 }
1095
1096 if (OMPInfoCache.OpenMPPostLink)
1097 Changed |= removeRuntimeSymbols();
1098
1099 return Changed;
1100 }
1101
1102 /// Print initial ICV values for testing.
1103 /// FIXME: This should be done from the Attributor once it is added.
1104 void printICVs() const {
1105 InternalControlVar ICVs[] = {ICV_nthreads, ICV_active_levels, ICV_cancel,
1106 ICV_proc_bind};
1107
1108 for (Function *F : SCC) {
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)
1113 << " Value: "
1114 << (ICVInfo.InitValue
1115 ? toString(ICVInfo.InitValue->getValue(), 10, true)
1116 : "IMPLEMENTATION_DEFINED");
1117 };
1118
1119 emitRemark<OptimizationRemarkAnalysis>(F, "OpenMPICVTracker", Remark);
1120 }
1121 }
1122 }
1123
1124 /// Print OpenMP GPU kernels for testing.
1125 void printKernels() const {
1126 for (Function *F : SCC) {
1127 if (!omp::isOpenMPKernel(*F))
1128 continue;
1129
1130 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
1131 return ORA << "OpenMP GPU kernel "
1132 << ore::NV("OpenMPGPUKernel", F->getName()) << "\n";
1133 };
1134
1136 }
1137 }
1138
1139 /// Return the call if \p U is a callee use in a regular call. If \p RFI is
1140 /// given it has to be the callee or a nullptr is returned.
1141 static CallInst *getCallIfRegularCall(
1142 Use &U, OMPInformationCache::RuntimeFunctionInfo *RFI = nullptr) {
1143 CallInst *CI = dyn_cast<CallInst>(U.getUser());
1144 if (CI && CI->isCallee(&U) && !CI->hasOperandBundles() &&
1145 (!RFI ||
1146 (RFI->Declaration && CI->getCalledFunction() == RFI->Declaration)))
1147 return CI;
1148 return nullptr;
1149 }
1150
1151 /// Return the call if \p V is a regular call. If \p RFI is given it has to be
1152 /// the callee or a nullptr is returned.
1153 static CallInst *getCallIfRegularCall(
1154 Value &V, OMPInformationCache::RuntimeFunctionInfo *RFI = nullptr) {
1155 CallInst *CI = dyn_cast<CallInst>(&V);
1156 if (CI && !CI->hasOperandBundles() &&
1157 (!RFI ||
1158 (RFI->Declaration && CI->getCalledFunction() == RFI->Declaration)))
1159 return CI;
1160 return nullptr;
1161 }
1162
1163private:
1164 /// Merge parallel regions when it is safe.
1165 bool mergeParallelRegions() {
1166 const unsigned CallbackCalleeOperand = 2;
1167 const unsigned CallbackFirstArgOperand = 3;
1168 using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
1169
1170 // Check if there are any __kmpc_fork_call calls to merge.
1171 OMPInformationCache::RuntimeFunctionInfo &RFI =
1172 OMPInfoCache.RFIs[OMPRTL___kmpc_fork_call];
1173
1174 if (!RFI.Declaration)
1175 return false;
1176
1177 // Unmergable calls that prevent merging a parallel region.
1178 OMPInformationCache::RuntimeFunctionInfo UnmergableCallsInfo[] = {
1179 OMPInfoCache.RFIs[OMPRTL___kmpc_push_proc_bind],
1180 OMPInfoCache.RFIs[OMPRTL___kmpc_push_num_threads],
1181 };
1182
1183 bool Changed = false;
1184 LoopInfo *LI = nullptr;
1185 DominatorTree *DT = nullptr;
1186
1187 SmallDenseMap<BasicBlock *, SmallPtrSet<Instruction *, 4>> BB2PRMap;
1188
1189 BasicBlock *StartBB = nullptr, *EndBB = nullptr;
1190 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
1191 ArrayRef<BasicBlock *> DeallocBlocks) {
1192 BasicBlock *CGStartBB = CodeGenIP.getNodeParent();
1193 BasicBlock *CGEndBB = SplitBlock(CGStartBB, &*CodeGenIP, DT, LI);
1194 assert(StartBB != nullptr && "StartBB should not be null");
1195 CGStartBB->getTerminator()->setSuccessor(0, StartBB);
1196 assert(EndBB != nullptr && "EndBB should not be null");
1197 EndBB->getTerminator()->setSuccessor(0, CGEndBB);
1198 return Error::success();
1199 };
1200
1201 auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, Value &,
1202 Value &Inner, Value *&ReplacementValue) -> InsertPointTy {
1203 ReplacementValue = &Inner;
1204 return CodeGenIP;
1205 };
1206
1207 auto FiniCB = [&](InsertPointTy CodeGenIP) { return Error::success(); };
1208
1209 /// Create a sequential execution region within a merged parallel region,
1210 /// encapsulated in a master construct with a barrier for synchronization.
1211 auto CreateSequentialRegion = [&](Function *OuterFn,
1212 BasicBlock *OuterPredBB,
1213 Instruction *SeqStartI,
1214 Instruction *SeqEndI) {
1215 // Isolate the instructions of the sequential region to a separate
1216 // block.
1217 BasicBlock *ParentBB = SeqStartI->getParent();
1218 BasicBlock *SeqEndBB =
1219 SplitBlock(ParentBB, SeqEndI->getNextNode(), DT, LI);
1220 BasicBlock *SeqAfterBB =
1221 SplitBlock(SeqEndBB, &*SeqEndBB->getFirstInsertionPt(), DT, LI);
1222 BasicBlock *SeqStartBB =
1223 SplitBlock(ParentBB, SeqStartI, DT, LI, nullptr, "seq.par.merged");
1224
1225 assert(ParentBB->getUniqueSuccessor() == SeqStartBB &&
1226 "Expected a different CFG");
1227 const DebugLoc DL = ParentBB->getTerminator()->getDebugLoc();
1228 ParentBB->getTerminator()->eraseFromParent();
1229
1230 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
1231 ArrayRef<BasicBlock *> DeallocBlocks) {
1232 BasicBlock *CGStartBB = CodeGenIP.getNodeParent();
1233 BasicBlock *CGEndBB = SplitBlock(CGStartBB, &*CodeGenIP, DT, LI);
1234 assert(SeqStartBB != nullptr && "SeqStartBB should not be null");
1235 CGStartBB->getTerminator()->setSuccessor(0, SeqStartBB);
1236 assert(SeqEndBB != nullptr && "SeqEndBB should not be null");
1237 SeqEndBB->getTerminator()->setSuccessor(0, CGEndBB);
1238 return Error::success();
1239 };
1240 auto FiniCB = [&](InsertPointTy CodeGenIP) { return Error::success(); };
1241
1242 // Find outputs from the sequential region to outside users and
1243 // broadcast their values to them.
1244 for (Instruction &I : *SeqStartBB) {
1245 SmallPtrSet<Instruction *, 4> OutsideUsers;
1246 for (User *Usr : I.users()) {
1247 Instruction &UsrI = *cast<Instruction>(Usr);
1248 // Ignore outputs to LT intrinsics, code extraction for the merged
1249 // parallel region will fix them.
1250 if (UsrI.isLifetimeStartOrEnd())
1251 continue;
1252
1253 if (UsrI.getParent() != SeqStartBB)
1254 OutsideUsers.insert(&UsrI);
1255 }
1256
1257 if (OutsideUsers.empty())
1258 continue;
1259
1260 // Emit an alloca in the outer region to store the broadcasted
1261 // value.
1262 const DataLayout &DL = M.getDataLayout();
1263 AllocaInst *AllocaI = new AllocaInst(
1264 I.getType(), DL.getAllocaAddrSpace(), nullptr,
1265 I.getName() + ".seq.output.alloc", OuterFn->front().begin());
1266
1267 // Emit a store instruction in the sequential BB to update the
1268 // value.
1269 new StoreInst(&I, AllocaI, SeqStartBB->getTerminator()->getIterator());
1270
1271 // Emit a load instruction and replace the use of the output value
1272 // with it.
1273 for (Instruction *UsrI : OutsideUsers) {
1274 LoadInst *LoadI = new LoadInst(I.getType(), AllocaI,
1275 I.getName() + ".seq.output.load",
1276 UsrI->getIterator());
1277 UsrI->replaceUsesOfWith(&I, LoadI);
1278 }
1279 }
1280
1281 OpenMPIRBuilder::LocationDescription Loc(ParentBB->end(), DL);
1283 OMPInfoCache.OMPBuilder.createMaster(Loc, BodyGenCB, FiniCB));
1284 cantFail(OMPInfoCache.OMPBuilder.createBarrier({SeqAfterIP, DL},
1285 OMPD_parallel));
1286
1287 UncondBrInst::Create(SeqAfterBB, SeqAfterIP.getNodeParent());
1288
1289 LLVM_DEBUG(dbgs() << TAG << "After sequential inlining " << *OuterFn
1290 << "\n");
1291 };
1292
1293 // Helper to merge the __kmpc_fork_call calls in MergableCIs. They are all
1294 // contained in BB and only separated by instructions that can be
1295 // redundantly executed in parallel. The block BB is split before the first
1296 // call (in MergableCIs) and after the last so the entire region we merge
1297 // into a single parallel region is contained in a single basic block
1298 // without any other instructions. We use the OpenMPIRBuilder to outline
1299 // that block and call the resulting function via __kmpc_fork_call.
1300 auto Merge = [&](const SmallVectorImpl<CallInst *> &MergableCIs,
1301 BasicBlock *BB) {
1302 // TODO: Change the interface to allow single CIs expanded, e.g, to
1303 // include an outer loop.
1304 assert(MergableCIs.size() > 1 && "Assumed multiple mergable CIs");
1305
1306 auto Remark = [&](OptimizationRemark OR) {
1307 OR << "Parallel region merged with parallel region"
1308 << (MergableCIs.size() > 2 ? "s" : "") << " at ";
1309 for (auto *CI : llvm::drop_begin(MergableCIs)) {
1310 OR << ore::NV("OpenMPParallelMerge", CI->getDebugLoc());
1311 if (CI != MergableCIs.back())
1312 OR << ", ";
1313 }
1314 return OR << ".";
1315 };
1316
1317 emitRemark<OptimizationRemark>(MergableCIs.front(), "OMP150", Remark);
1318
1319 Function *OriginalFn = BB->getParent();
1320 LLVM_DEBUG(dbgs() << TAG << "Merge " << MergableCIs.size()
1321 << " parallel regions in " << OriginalFn->getName()
1322 << "\n");
1323
1324 // Isolate the calls to merge in a separate block.
1325 EndBB = SplitBlock(BB, MergableCIs.back()->getNextNode(), DT, LI);
1326 BasicBlock *AfterBB =
1327 SplitBlock(EndBB, &*EndBB->getFirstInsertionPt(), DT, LI);
1328 StartBB = SplitBlock(BB, MergableCIs.front(), DT, LI, nullptr,
1329 "omp.par.merged");
1330
1331 assert(BB->getUniqueSuccessor() == StartBB && "Expected a different CFG");
1332 const DebugLoc DL = BB->getTerminator()->getDebugLoc();
1333 BB->getTerminator()->eraseFromParent();
1334
1335 // Create sequential regions for sequential instructions that are
1336 // in-between mergable parallel regions.
1337 for (auto *It = MergableCIs.begin(), *End = MergableCIs.end() - 1;
1338 It != End; ++It) {
1339 Instruction *ForkCI = *It;
1340 Instruction *NextForkCI = *(It + 1);
1341
1342 // Continue if there are not in-between instructions.
1343 if (ForkCI->getNextNode() == NextForkCI)
1344 continue;
1345
1346 CreateSequentialRegion(OriginalFn, BB, ForkCI->getNextNode(),
1347 NextForkCI->getPrevNode());
1348 }
1349
1350 OpenMPIRBuilder::LocationDescription Loc(BB->end(), DL);
1351 IRBuilder<>::InsertPoint AllocaIP(
1352 OriginalFn->getEntryBlock().getFirstInsertionPt());
1353 // Create the merged parallel region with default proc binding, to
1354 // avoid overriding binding settings, and without explicit cancellation.
1356 cantFail(OMPInfoCache.OMPBuilder.createParallel(
1357 Loc, AllocaIP, /* DeallocBlocks */ {}, BodyGenCB, PrivCB, FiniCB,
1358 nullptr, nullptr, OMP_PROC_BIND_default,
1359 /* IsCancellable */ false));
1360 UncondBrInst::Create(AfterBB, AfterIP.getNodeParent());
1361
1362 // Perform the actual outlining.
1363 OMPInfoCache.OMPBuilder.finalize(OriginalFn);
1364
1365 Function *OutlinedFn = MergableCIs.front()->getCaller();
1366 std::optional<uint64_t> WrapperCount =
1367 getMergedWrapperEntryCount(MergableCIs, CallbackCalleeOperand);
1368 // Leave the wrapper unprofiled when no callback has an entry count.
1369 if (WrapperCount)
1370 OutlinedFn->setEntryCount(*WrapperCount);
1371 // Only sample PGO treats a profiled caller with no callsite weight as
1372 // cold. Instrumentation profiles derive that count from the entry count.
1373 const bool SampleProfile =
1374 moduleHasSampleProfile(*OriginalFn->getParent());
1375
1376 // Replace the __kmpc_fork_call calls with direct calls to the outlined
1377 // callbacks.
1378 SmallVector<Value *, 8> Args;
1379 for (auto *CI : MergableCIs) {
1380 Value *Callee = CI->getArgOperand(CallbackCalleeOperand);
1381 FunctionType *FT = OMPInfoCache.OMPBuilder.ParallelTask;
1382 Args.clear();
1383 Args.push_back(OutlinedFn->getArg(0));
1384 Args.push_back(OutlinedFn->getArg(1));
1385 for (unsigned U = CallbackFirstArgOperand, E = CI->arg_size(); U < E;
1386 ++U)
1387 Args.push_back(CI->getArgOperand(U));
1388
1389 CallInst *NewCI =
1390 CallInst::Create(FT, Callee, Args, "", CI->getIterator());
1391 if (CI->getDebugLoc())
1392 NewCI->setDebugLoc(CI->getDebugLoc());
1393 // Each body runs once per wrapper entry. Without a callsite weight,
1394 // sample PGO treats these calls as cold.
1395 if (WrapperCount && SampleProfile) {
1396 setFittedBranchWeights(*NewCI, {*WrapperCount},
1397 /*IsExpected=*/false);
1398 }
1399
1400 // Forward parameter attributes from the callback to the callee.
1401 for (unsigned U = CallbackFirstArgOperand, E = CI->arg_size(); U < E;
1402 ++U)
1403 for (const Attribute &A : CI->getAttributes().getParamAttrs(U))
1404 NewCI->addParamAttr(
1405 U - (CallbackFirstArgOperand - CallbackCalleeOperand), A);
1406
1407 // Emit an explicit barrier to replace the implicit fork-join barrier.
1408 if (CI != MergableCIs.back()) {
1409 // TODO: Remove barrier if the merged parallel region includes the
1410 // 'nowait' clause.
1411 cantFail(OMPInfoCache.OMPBuilder.createBarrier(
1412 {NewCI->getNextNode()->getIterator(), NewCI->getDebugLoc()},
1413 OMPD_parallel));
1414 }
1415
1416 CI->eraseFromParent();
1417 }
1418
1419 assert(OutlinedFn != OriginalFn && "Outlining failed");
1420 CGUpdater.registerOutlinedFunction(*OriginalFn, *OutlinedFn);
1421 CGUpdater.reanalyzeFunction(*OriginalFn);
1422
1423 NumOpenMPParallelRegionsMerged += MergableCIs.size();
1424
1425 return true;
1426 };
1427
1428 // Helper function that identifes sequences of
1429 // __kmpc_fork_call uses in a basic block.
1430 auto DetectPRsCB = [&](Use &U, Function &F) {
1431 CallInst *CI = getCallIfRegularCall(U, &RFI);
1432 BB2PRMap[CI->getParent()].insert(CI);
1433
1434 return false;
1435 };
1436
1437 BB2PRMap.clear();
1438 RFI.foreachUse(SCC, DetectPRsCB);
1439 SmallVector<SmallVector<CallInst *, 4>, 4> MergableCIsVector;
1440 // Find mergable parallel regions within a basic block that are
1441 // safe to merge, that is any in-between instructions can safely
1442 // execute in parallel after merging.
1443 // TODO: support merging across basic-blocks.
1444 for (auto &It : BB2PRMap) {
1445 auto &CIs = It.getSecond();
1446 if (CIs.size() < 2)
1447 continue;
1448
1449 BasicBlock *BB = It.getFirst();
1450 SmallVector<CallInst *, 4> MergableCIs;
1451
1452 /// Returns true if the instruction is mergable, false otherwise.
1453 /// A terminator instruction is unmergable by definition since merging
1454 /// works within a BB. Instructions before the mergable region are
1455 /// mergable if they are not calls to OpenMP runtime functions that may
1456 /// set different execution parameters for subsequent parallel regions.
1457 /// Instructions in-between parallel regions are mergable if they are not
1458 /// calls to any non-intrinsic function since that may call a non-mergable
1459 /// OpenMP runtime function.
1460 auto IsMergable = [&](Instruction &I, bool IsBeforeMergableRegion) {
1461 // We do not merge across BBs, hence return false (unmergable) if the
1462 // instruction is a terminator.
1463 if (I.isTerminator())
1464 return false;
1465
1466 if (!isa<CallInst>(&I))
1467 return true;
1468
1469 CallInst *CI = cast<CallInst>(&I);
1470 if (IsBeforeMergableRegion) {
1471 Function *CalledFunction = CI->getCalledFunction();
1472 if (!CalledFunction)
1473 return false;
1474 // Return false (unmergable) if the call before the parallel
1475 // region calls an explicit affinity (proc_bind) or number of
1476 // threads (num_threads) compiler-generated function. Those settings
1477 // may be incompatible with following parallel regions.
1478 // TODO: ICV tracking to detect compatibility.
1479 for (const auto &RFI : UnmergableCallsInfo) {
1480 if (CalledFunction == RFI.Declaration)
1481 return false;
1482 }
1483 } else {
1484 // Return false (unmergable) if there is a call instruction
1485 // in-between parallel regions when it is not an intrinsic. It
1486 // may call an unmergable OpenMP runtime function in its callpath.
1487 // TODO: Keep track of possible OpenMP calls in the callpath.
1488 if (!isa<IntrinsicInst>(CI))
1489 return false;
1490 }
1491
1492 return true;
1493 };
1494 // Find maximal number of parallel region CIs that are safe to merge.
1495 for (auto It = BB->begin(), End = BB->end(); It != End;) {
1496 Instruction &I = *It;
1497 ++It;
1498
1499 if (CIs.count(&I)) {
1500 MergableCIs.push_back(cast<CallInst>(&I));
1501 continue;
1502 }
1503
1504 // Continue expanding if the instruction is mergable.
1505 if (IsMergable(I, MergableCIs.empty()))
1506 continue;
1507
1508 // Forward the instruction iterator to skip the next parallel region
1509 // since there is an unmergable instruction which can affect it.
1510 for (; It != End; ++It) {
1511 Instruction &SkipI = *It;
1512 if (CIs.count(&SkipI)) {
1513 LLVM_DEBUG(dbgs() << TAG << "Skip parallel region " << SkipI
1514 << " due to " << I << "\n");
1515 ++It;
1516 break;
1517 }
1518 }
1519
1520 // Store mergable regions found.
1521 if (MergableCIs.size() > 1) {
1522 MergableCIsVector.push_back(MergableCIs);
1523 LLVM_DEBUG(dbgs() << TAG << "Found " << MergableCIs.size()
1524 << " parallel regions in block " << BB->getName()
1525 << " of function " << BB->getParent()->getName()
1526 << "\n";);
1527 }
1528
1529 MergableCIs.clear();
1530 }
1531
1532 if (!MergableCIsVector.empty()) {
1533 Changed = true;
1534
1535 for (auto &MergableCIs : MergableCIsVector)
1536 Merge(MergableCIs, BB);
1537 MergableCIsVector.clear();
1538 }
1539 }
1540
1541 if (Changed) {
1542 /// Re-collect use for fork calls, emitted barrier calls, and
1543 /// any emitted master/end_master calls.
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);
1548 }
1549
1550 return Changed;
1551 }
1552
1553 /// Try to delete parallel regions if possible.
1554 bool deleteParallelRegions() {
1555 const unsigned CallbackCalleeOperand = 2;
1556
1557 OMPInformationCache::RuntimeFunctionInfo &RFI =
1558 OMPInfoCache.RFIs[OMPRTL___kmpc_fork_call];
1559
1560 if (!RFI.Declaration)
1561 return false;
1562
1563 bool Changed = false;
1564 auto DeleteCallCB = [&](Use &U, Function &) {
1565 CallInst *CI = getCallIfRegularCall(U);
1566 if (!CI)
1567 return false;
1568 auto *Fn = dyn_cast<Function>(
1569 CI->getArgOperand(CallbackCalleeOperand)->stripPointerCasts());
1570 if (!Fn)
1571 return false;
1572 if (!Fn->onlyReadsMemory())
1573 return false;
1574 if (!Fn->hasFnAttribute(Attribute::WillReturn))
1575 return false;
1576
1577 LLVM_DEBUG(dbgs() << TAG << "Delete read-only parallel region in "
1578 << CI->getCaller()->getName() << "\n");
1579
1580 auto Remark = [&](OptimizationRemark OR) {
1581 return OR << "Removing parallel region with no side-effects.";
1582 };
1584
1585 CI->eraseFromParent();
1586 Changed = true;
1587 ++NumOpenMPParallelRegionsDeleted;
1588 return true;
1589 };
1590
1591 RFI.foreachUse(SCC, DeleteCallCB);
1592
1593 return Changed;
1594 }
1595
1596 /// Try to eliminate runtime calls by reusing existing ones.
1597 bool deduplicateRuntimeCalls() {
1598 bool Changed = false;
1599
1600 RuntimeFunction DeduplicableRuntimeCallIDs[] = {
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};
1616
1617 // Global-tid is handled separately.
1618 SmallSetVector<Value *, 16> GTIdArgs;
1619 collectGlobalThreadIdArguments(GTIdArgs);
1620 LLVM_DEBUG(dbgs() << TAG << "Found " << GTIdArgs.size()
1621 << " global thread ID arguments\n");
1622
1623 for (Function *F : SCC) {
1624 for (auto DeduplicableRuntimeCallID : DeduplicableRuntimeCallIDs)
1625 Changed |= deduplicateRuntimeCalls(
1626 *F, OMPInfoCache.RFIs[DeduplicableRuntimeCallID]);
1627
1628 // __kmpc_global_thread_num is special as we can replace it with an
1629 // argument in enough cases to make it worth trying.
1630 Value *GTIdArg = nullptr;
1631 for (Argument &Arg : F->args())
1632 if (GTIdArgs.count(&Arg)) {
1633 GTIdArg = &Arg;
1634 break;
1635 }
1636 Changed |= deduplicateRuntimeCalls(
1637 *F, OMPInfoCache.RFIs[OMPRTL___kmpc_global_thread_num], GTIdArg);
1638 }
1639
1640 return Changed;
1641 }
1642
1643 /// Tries to remove known runtime symbols that are optional from the module.
1644 bool removeRuntimeSymbols() {
1645 // The RPC client symbol is defined in `libc` and indicates that something
1646 // required an RPC server. If its users were all optimized out then we can
1647 // safely remove it.
1648 // TODO: This should be somewhere more common in the future.
1649 if (GlobalVariable *GV = M.getNamedGlobal("__llvm_rpc_client")) {
1650 if (GV->hasNUsesOrMore(1))
1651 return false;
1652
1653 GV->replaceAllUsesWith(PoisonValue::get(GV->getType()));
1654 GV->eraseFromParent();
1655 return true;
1656 }
1657 return false;
1658 }
1659
1660 /// Tries to hide the latency of runtime calls that involve host to
1661 /// device memory transfers by splitting them into their "issue" and "wait"
1662 /// versions. The "issue" is moved upwards as much as possible. The "wait" is
1663 /// moved downards as much as possible. The "issue" issues the memory transfer
1664 /// asynchronously, returning a handle. The "wait" waits in the returned
1665 /// handle for the memory transfer to finish.
1666 bool hideMemTransfersLatency() {
1667 auto &RFI = OMPInfoCache.RFIs[OMPRTL___tgt_target_data_begin_mapper];
1668 bool Changed = false;
1669 auto SplitMemTransfers = [&](Use &U, Function &Decl) {
1670 auto *RTCall = getCallIfRegularCall(U, &RFI);
1671 if (!RTCall)
1672 return false;
1673
1674 OffloadArray OffloadArrays[3];
1675 if (!getValuesInOffloadArrays(*RTCall, OffloadArrays))
1676 return false;
1677
1678 LLVM_DEBUG(dumpValuesInOffloadArrays(OffloadArrays));
1679
1680 // TODO: Check if can be moved upwards.
1681 bool WasSplit = false;
1682 Instruction *WaitMovementPoint = canBeMovedDownwards(*RTCall);
1683 if (WaitMovementPoint)
1684 WasSplit = splitTargetDataBeginRTC(*RTCall, *WaitMovementPoint);
1685
1686 Changed |= WasSplit;
1687 return WasSplit;
1688 };
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);
1693
1694 return Changed;
1695 }
1696
1697 void analysisGlobalization() {
1698 auto &RFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
1699
1700 auto CheckGlobalization = [&](Use &U, Function &Decl) {
1701 if (CallInst *CI = getCallIfRegularCall(U, &RFI)) {
1702 auto Remark = [&](OptimizationRemarkMissed ORM) {
1703 return ORM
1704 << "Found thread data sharing on the GPU. "
1705 << "Expect degraded performance due to data globalization.";
1706 };
1708 }
1709
1710 return false;
1711 };
1712
1713 RFI.foreachUse(SCC, CheckGlobalization);
1714 }
1715
1716 /// Maps the values stored in the offload arrays passed as arguments to
1717 /// \p RuntimeCall into the offload arrays in \p OAs.
1718 bool getValuesInOffloadArrays(CallInst &RuntimeCall,
1720 assert(OAs.size() == 3 && "Need space for three offload arrays!");
1721
1722 // A runtime call that involves memory offloading looks something like:
1723 // call void @__tgt_target_data_begin_mapper(arg0, arg1,
1724 // i8** %offload_baseptrs, i8** %offload_ptrs, i64* %offload_sizes,
1725 // ...)
1726 // So, the idea is to access the allocas that allocate space for these
1727 // offload arrays, offload_baseptrs, offload_ptrs, offload_sizes.
1728 // Therefore:
1729 // i8** %offload_baseptrs.
1730 Value *BasePtrsArg =
1731 RuntimeCall.getArgOperand(OffloadArray::BasePtrsArgNum);
1732 // i8** %offload_ptrs.
1733 Value *PtrsArg = RuntimeCall.getArgOperand(OffloadArray::PtrsArgNum);
1734 // i8** %offload_sizes.
1735 Value *SizesArg = RuntimeCall.getArgOperand(OffloadArray::SizesArgNum);
1736
1737 // Get values stored in **offload_baseptrs.
1738 auto *V = getUnderlyingObject(BasePtrsArg);
1739 if (!isa<AllocaInst>(V))
1740 return false;
1741 auto *BasePtrsArray = cast<AllocaInst>(V);
1742 if (!OAs[0].initialize(*BasePtrsArray, RuntimeCall))
1743 return false;
1744
1745 // Get values stored in **offload_baseptrs.
1746 V = getUnderlyingObject(PtrsArg);
1747 if (!isa<AllocaInst>(V))
1748 return false;
1749 auto *PtrsArray = cast<AllocaInst>(V);
1750 if (!OAs[1].initialize(*PtrsArray, RuntimeCall))
1751 return false;
1752
1753 // Get values stored in **offload_sizes.
1754 V = getUnderlyingObject(SizesArg);
1755 // If it's a [constant] global array don't analyze it.
1756 if (isa<GlobalValue>(V))
1757 return isa<Constant>(V);
1758 if (!isa<AllocaInst>(V))
1759 return false;
1760
1761 auto *SizesArray = cast<AllocaInst>(V);
1762 if (!OAs[2].initialize(*SizesArray, RuntimeCall))
1763 return false;
1764
1765 return true;
1766 }
1767
1768 /// Prints the values in the OffloadArrays \p OAs using LLVM_DEBUG.
1769 /// For now this is a way to test that the function getValuesInOffloadArrays
1770 /// is working properly.
1771 /// TODO: Move this to a unittest when unittests are available for OpenMPOpt.
1772 void dumpValuesInOffloadArrays(ArrayRef<OffloadArray> OAs) {
1773 assert(OAs.size() == 3 && "There are three offload arrays to debug!");
1774
1775 LLVM_DEBUG(dbgs() << TAG << " Successfully got offload values:\n");
1776 std::string ValuesStr;
1777 raw_string_ostream Printer(ValuesStr);
1778 std::string Separator = " --- ";
1779
1780 for (auto *BP : OAs[0].StoredValues) {
1781 BP->print(Printer);
1782 Printer << Separator;
1783 }
1784 LLVM_DEBUG(dbgs() << "\t\toffload_baseptrs: " << ValuesStr << "\n");
1785 ValuesStr.clear();
1786
1787 for (auto *P : OAs[1].StoredValues) {
1788 P->print(Printer);
1789 Printer << Separator;
1790 }
1791 LLVM_DEBUG(dbgs() << "\t\toffload_ptrs: " << ValuesStr << "\n");
1792 ValuesStr.clear();
1793
1794 for (auto *S : OAs[2].StoredValues) {
1795 S->print(Printer);
1796 Printer << Separator;
1797 }
1798 LLVM_DEBUG(dbgs() << "\t\toffload_sizes: " << ValuesStr << "\n");
1799 }
1800
1801 /// Returns the instruction where the "wait" counterpart \p RuntimeCall can be
1802 /// moved. Returns nullptr if the movement is not possible, or not worth it.
1803 Instruction *canBeMovedDownwards(CallInst &RuntimeCall) {
1804 // FIXME: This traverses only the BasicBlock where RuntimeCall is.
1805 // Make it traverse the CFG.
1806
1807 Instruction *CurrentI = &RuntimeCall;
1808 bool IsWorthIt = false;
1809 while ((CurrentI = CurrentI->getNextNode())) {
1810
1811 // TODO: Once we detect the regions to be offloaded we should use the
1812 // alias analysis manager to check if CurrentI may modify one of
1813 // the offloaded regions.
1814 if (CurrentI->mayHaveSideEffects() || CurrentI->mayReadFromMemory()) {
1815 if (IsWorthIt)
1816 return CurrentI;
1817
1818 return nullptr;
1819 }
1820
1821 // FIXME: For now if we move it over anything without side effect
1822 // is worth it.
1823 IsWorthIt = true;
1824 }
1825
1826 // Return end of BasicBlock.
1827 return RuntimeCall.getParent()->getTerminator();
1828 }
1829
1830 /// Splits \p RuntimeCall into its "issue" and "wait" counterparts.
1831 bool splitTargetDataBeginRTC(CallInst &RuntimeCall,
1832 Instruction &WaitMovementPoint) {
1833 // Create stack allocated handle (__tgt_async_info) at the beginning of the
1834 // function. Used for storing information of the async transfer, allowing to
1835 // wait on it later.
1836 auto &IRBuilder = OMPInfoCache.OMPBuilder;
1837 Function *F = RuntimeCall.getCaller();
1838 BasicBlock &Entry = F->getEntryBlock();
1839 IRBuilder.Builder.SetInsertPoint(Entry.getFirstNonPHIOrAlloca());
1840 Value *Handle = IRBuilder.Builder.CreateAlloca(
1841 IRBuilder.AsyncInfo, /*ArraySize=*/nullptr, "handle");
1842 Handle =
1843 IRBuilder.Builder.CreateAddrSpaceCast(Handle, IRBuilder.AsyncInfoPtr);
1844
1845 // Add "issue" runtime call declaration:
1846 // declare %struct.tgt_async_info @__tgt_target_data_begin_issue(i64, i32,
1847 // i8**, i8**, i64*, i64*)
1848 FunctionCallee IssueDecl = IRBuilder.getOrCreateRuntimeFunction(
1849 M, OMPRTL___tgt_target_data_begin_mapper_issue);
1850
1851 // Change RuntimeCall call site for its asynchronous version.
1852 SmallVector<Value *, 16> Args;
1853 for (auto &Arg : RuntimeCall.args())
1854 Args.push_back(Arg.get());
1855 Args.push_back(Handle);
1856
1857 CallInst *IssueCallsite = CallInst::Create(IssueDecl, Args, /*NameStr=*/"",
1858 RuntimeCall.getIterator());
1859 OMPInfoCache.setCallingConvention(IssueDecl, IssueCallsite);
1860 RuntimeCall.eraseFromParent();
1861
1862 // Add "wait" runtime call declaration:
1863 // declare void @__tgt_target_data_begin_wait(i64, %struct.__tgt_async_info)
1864 FunctionCallee WaitDecl = IRBuilder.getOrCreateRuntimeFunction(
1865 M, OMPRTL___tgt_target_data_begin_mapper_wait);
1866
1867 Value *WaitParams[2] = {
1868 IssueCallsite->getArgOperand(
1869 OffloadArray::DeviceIDArgNum), // device_id.
1870 Handle // handle to wait on.
1871 };
1872 CallInst *WaitCallsite = CallInst::Create(
1873 WaitDecl, WaitParams, /*NameStr=*/"", WaitMovementPoint.getIterator());
1874 OMPInfoCache.setCallingConvention(WaitDecl, WaitCallsite);
1875
1876 return true;
1877 }
1878
1879 static Value *combinedIdentStruct(Value *CurrentIdent, Value *NextIdent,
1880 bool GlobalOnly, bool &SingleChoice) {
1881 if (CurrentIdent == NextIdent)
1882 return CurrentIdent;
1883
1884 // TODO: Figure out how to actually combine multiple debug locations. For
1885 // now we just keep an existing one if there is a single choice.
1886 if (!GlobalOnly || isa<GlobalValue>(NextIdent)) {
1887 SingleChoice = !CurrentIdent;
1888 return NextIdent;
1889 }
1890 return nullptr;
1891 }
1892
1893 /// Return an `struct ident_t*` value that represents the ones used in the
1894 /// calls of \p RFI inside of \p F. If \p GlobalOnly is true, we will not
1895 /// return a local `struct ident_t*`. For now, if we cannot find a suitable
1896 /// return value we create one from scratch. We also do not yet combine
1897 /// information, e.g., the source locations, see combinedIdentStruct.
1898 Value *
1899 getCombinedIdentFromCallUsesIn(OMPInformationCache::RuntimeFunctionInfo &RFI,
1900 Function &F, bool GlobalOnly) {
1901 bool SingleChoice = true;
1902 Value *Ident = nullptr;
1903 auto CombineIdentStruct = [&](Use &U, Function &Caller) {
1904 CallInst *CI = getCallIfRegularCall(U, &RFI);
1905 if (!CI || &F != &Caller)
1906 return false;
1907 Ident = combinedIdentStruct(Ident, CI->getArgOperand(0),
1908 /* GlobalOnly */ true, SingleChoice);
1909 return false;
1910 };
1911 RFI.foreachUse(SCC, CombineIdentStruct);
1912
1913 if (!Ident || !SingleChoice) {
1914 // The IRBuilder uses the insertion block to get to the module, this is
1915 // unfortunate but we work around it for now. No instruction is emitted
1916 // here, so there is no debug location to preserve.
1917 if (!OMPInfoCache.OMPBuilder.getInsertionPoint().isValid())
1918 OMPInfoCache.OMPBuilder.updateToLocation(
1919 {F.getEntryBlock().begin(), DebugLoc()});
1920 // Create a fallback location if non was found.
1921 // TODO: Use the debug locations of the calls instead.
1922 uint32_t SrcLocStrSize;
1923 Constant *Loc =
1924 OMPInfoCache.OMPBuilder.getOrCreateDefaultSrcLocStr(SrcLocStrSize);
1925 Ident = OMPInfoCache.OMPBuilder.getOrCreateIdent(Loc, SrcLocStrSize);
1926 }
1927 return Ident;
1928 }
1929
1930 /// Try to eliminate calls of \p RFI in \p F by reusing an existing one or
1931 /// \p ReplVal if given.
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)
1937 return false;
1938
1939 LLVM_DEBUG(
1940 dbgs() << TAG << "Deduplicate " << UV->size() << " uses of " << RFI.Name
1941 << (ReplVal ? " with an existing value\n" : "\n") << "\n");
1942
1943 assert((!ReplVal || (isa<Argument>(ReplVal) &&
1944 cast<Argument>(ReplVal)->getParent() == &F)) &&
1945 "Unexpected replacement value!");
1946
1947 // TODO: Use dominance to find a good position instead.
1948 auto CanBeMoved = [this](CallBase &CB) {
1949 unsigned NumArgs = CB.arg_size();
1950 if (NumArgs == 0)
1951 return true;
1952 if (CB.getArgOperand(0)->getType() != OMPInfoCache.OMPBuilder.IdentPtr)
1953 return false;
1954 for (unsigned U = 1; U < NumArgs; ++U)
1956 return false;
1957 return true;
1958 };
1959
1960 if (!ReplVal) {
1961 auto *DT =
1962 OMPInfoCache.getAnalysisResultForFunction<DominatorTreeAnalysis>(F);
1963 if (!DT)
1964 return false;
1965 Instruction *IP = nullptr;
1966 for (Use *U : *UV) {
1967 if (CallInst *CI = getCallIfRegularCall(*U, &RFI)) {
1968 if (IP)
1969 IP = DT->findNearestCommonDominator(IP, CI);
1970 else
1971 IP = CI;
1972 if (!CanBeMoved(*CI))
1973 continue;
1974 if (!ReplVal)
1975 ReplVal = CI;
1976 }
1977 }
1978 if (!ReplVal)
1979 return false;
1980 assert(IP && "Expected insertion point!");
1981 cast<Instruction>(ReplVal)->moveBefore(IP->getIterator());
1982 }
1983
1984 // If we use a call as a replacement value we need to make sure the ident is
1985 // valid at the new location. For now we just pick a global one, either
1986 // existing and used by one of the calls, or created from scratch.
1987 if (CallBase *CI = dyn_cast<CallBase>(ReplVal)) {
1988 if (!CI->arg_empty() &&
1989 CI->getArgOperand(0)->getType() == OMPInfoCache.OMPBuilder.IdentPtr) {
1990 Value *Ident = getCombinedIdentFromCallUsesIn(RFI, F,
1991 /* GlobalOnly */ true);
1992 CI->setArgOperand(0, Ident);
1993 }
1994 }
1995
1996 bool Changed = false;
1997 auto ReplaceAndDeleteCB = [&](Use &U, Function &Caller) {
1998 CallInst *CI = getCallIfRegularCall(U, &RFI);
1999 if (!CI || CI == ReplVal || &F != &Caller)
2000 return false;
2001 assert(CI->getCaller() == &F && "Unexpected call!");
2002
2003 auto Remark = [&](OptimizationRemark OR) {
2004 return OR << "OpenMP runtime call "
2005 << ore::NV("OpenMPOptRuntime", RFI.Name) << " deduplicated.";
2006 };
2007 if (CI->getDebugLoc())
2009 else
2011
2012 CI->replaceAllUsesWith(ReplVal);
2013 CI->eraseFromParent();
2014 ++NumOpenMPRuntimeCallsDeduplicated;
2015 Changed = true;
2016 return true;
2017 };
2018 RFI.foreachUse(SCC, ReplaceAndDeleteCB);
2019
2020 return Changed;
2021 }
2022
2023 /// Collect arguments that represent the global thread id in \p GTIdArgs.
2024 void collectGlobalThreadIdArguments(SmallSetVector<Value *, 16> &GTIdArgs) {
2025 // TODO: Below we basically perform a fixpoint iteration with a pessimistic
2026 // initialization. We could define an AbstractAttribute instead and
2027 // run the Attributor here once it can be run as an SCC pass.
2028
2029 // Helper to check the argument \p ArgNo at all call sites of \p F for
2030 // a GTId.
2031 auto CallArgOpIsGTId = [&](Function &F, unsigned ArgNo, CallInst &RefCI) {
2032 if (!F.hasLocalLinkage())
2033 return false;
2034 for (Use &U : F.uses()) {
2035 if (CallInst *CI = getCallIfRegularCall(U)) {
2036 Value *ArgOp = CI->getArgOperand(ArgNo);
2037 if (CI == &RefCI || GTIdArgs.count(ArgOp) ||
2038 getCallIfRegularCall(
2039 *ArgOp, &OMPInfoCache.RFIs[OMPRTL___kmpc_global_thread_num]))
2040 continue;
2041 }
2042 return false;
2043 }
2044 return true;
2045 };
2046
2047 // Helper to identify uses of a GTId as GTId arguments.
2048 auto AddUserArgs = [&](Value &GTId) {
2049 for (Use &U : GTId.uses())
2050 if (CallInst *CI = dyn_cast<CallInst>(U.getUser()))
2051 if (CI->isArgOperand(&U))
2052 if (Function *Callee = CI->getCalledFunction())
2053 if (CallArgOpIsGTId(*Callee, U.getOperandNo(), *CI))
2054 GTIdArgs.insert(Callee->getArg(U.getOperandNo()));
2055 };
2056
2057 // The argument users of __kmpc_global_thread_num calls are GTIds.
2058 OMPInformationCache::RuntimeFunctionInfo &GlobThreadNumRFI =
2059 OMPInfoCache.RFIs[OMPRTL___kmpc_global_thread_num];
2060
2061 GlobThreadNumRFI.foreachUse(SCC, [&](Use &U, Function &F) {
2062 if (CallInst *CI = getCallIfRegularCall(U, &GlobThreadNumRFI))
2063 AddUserArgs(*CI);
2064 return false;
2065 });
2066
2067 // Transitively search for more arguments by looking at the users of the
2068 // ones we know already. During the search the GTIdArgs vector is extended
2069 // so we cannot cache the size nor can we use a range based for.
2070 for (unsigned U = 0; U < GTIdArgs.size(); ++U)
2071 AddUserArgs(*GTIdArgs[U]);
2072 }
2073
2074 /// Kernel (=GPU) optimizations and utility functions
2075 ///
2076 ///{{
2077
2078 /// Cache to remember the unique kernel for a function.
2079 DenseMap<Function *, std::optional<Kernel>> UniqueKernelMap;
2080
2081 /// Find the unique kernel that will execute \p F, if any.
2082 Kernel getUniqueKernelFor(Function &F);
2083
2084 /// Find the unique kernel that will execute \p I, if any.
2085 Kernel getUniqueKernelFor(Instruction &I) {
2086 return getUniqueKernelFor(*I.getFunction());
2087 }
2088
2089 /// Rewrite the device (=GPU) code state machine create in non-SPMD mode in
2090 /// the cases we can avoid taking the address of a function.
2091 bool rewriteDeviceCodeStateMachine();
2092
2093 /// In SPMD kernels the parallel data-sharing wrapper passed to
2094 /// __kmpc_parallel_60 is never used by the runtime; null it out so the dead
2095 /// wrapper (and any LDS it references) can be removed.
2096 bool removeSPMDParallelWrappers();
2097
2098 ///
2099 ///}}
2100
2101 /// Emit a remark generically
2102 ///
2103 /// This template function can be used to generically emit a remark. The
2104 /// RemarkKind should be one of the following:
2105 /// - OptimizationRemark to indicate a successful optimization attempt
2106 /// - OptimizationRemarkMissed to report a failed optimization attempt
2107 /// - OptimizationRemarkAnalysis to provide additional information about an
2108 /// optimization attempt
2109 ///
2110 /// The remark is built using a callback function provided by the caller that
2111 /// takes a RemarkKind as input and returns a RemarkKind.
2112 template <typename RemarkKind, typename RemarkCallBack>
2113 void emitRemark(Instruction *I, StringRef RemarkName,
2114 RemarkCallBack &&RemarkCB) const {
2115 Function *F = I->getParent()->getParent();
2116 auto &ORE = OREGetter(F);
2117
2118 if (RemarkName.starts_with("OMP"))
2119 ORE.emit([&]() {
2120 return RemarkCB(RemarkKind(DEBUG_TYPE, RemarkName, I))
2121 << " [" << RemarkName << "]";
2122 });
2123 else
2124 ORE.emit(
2125 [&]() { return RemarkCB(RemarkKind(DEBUG_TYPE, RemarkName, I)); });
2126 }
2127
2128 /// Emit a remark on a function.
2129 template <typename RemarkKind, typename RemarkCallBack>
2130 void emitRemark(Function *F, StringRef RemarkName,
2131 RemarkCallBack &&RemarkCB) const {
2132 auto &ORE = OREGetter(F);
2133
2134 if (RemarkName.starts_with("OMP"))
2135 ORE.emit([&]() {
2136 return RemarkCB(RemarkKind(DEBUG_TYPE, RemarkName, F))
2137 << " [" << RemarkName << "]";
2138 });
2139 else
2140 ORE.emit(
2141 [&]() { return RemarkCB(RemarkKind(DEBUG_TYPE, RemarkName, F)); });
2142 }
2143
2144 /// The underlying module.
2145 Module &M;
2146
2147 /// The SCC we are operating on.
2148 SmallVectorImpl<Function *> &SCC;
2149
2150 /// Callback to update the call graph, the first argument is a removed call,
2151 /// the second an optional replacement call.
2152 CallGraphUpdater &CGUpdater;
2153
2154 /// Callback to get an OptimizationRemarkEmitter from a Function *
2155 OptimizationRemarkGetter OREGetter;
2156
2157 /// OpenMP-specific information cache. Also Used for Attributor runs.
2158 OMPInformationCache &OMPInfoCache;
2159
2160 /// Attributor instance.
2161 Attributor &A;
2162
2163 /// Helper function to run Attributor on SCC.
2164 bool runAttributor(bool IsModulePass) {
2165 if (SCC.empty())
2166 return false;
2167
2168 registerAAs(IsModulePass);
2169
2170 ChangeStatus Changed = A.run();
2171
2172 LLVM_DEBUG(dbgs() << "[Attributor] Done with " << SCC.size()
2173 << " functions, result: " << Changed << ".\n");
2174
2175 if (Changed == ChangeStatus::CHANGED)
2176 OMPInfoCache.invalidateAnalyses();
2177
2178 return Changed == ChangeStatus::CHANGED;
2179 }
2180
2181 void registerFoldRuntimeCall(RuntimeFunction RF);
2182
2183 /// Populate the Attributor with abstract attribute opportunities in the
2184 /// functions.
2185 void registerAAs(bool IsModulePass);
2186
2187public:
2188 /// Callback to register AAs for live functions, including internal functions
2189 /// marked live during the traversal.
2190 static void registerAAsForFunction(Attributor &A, const Function &F);
2191};
2192
2193Kernel OpenMPOpt::getUniqueKernelFor(Function &F) {
2194 if (OMPInfoCache.CGSCC && !OMPInfoCache.CGSCC->empty() &&
2195 !OMPInfoCache.CGSCC->contains(&F))
2196 return nullptr;
2197
2198 // Use a scope to keep the lifetime of the CachedKernel short.
2199 {
2200 std::optional<Kernel> &CachedKernel = UniqueKernelMap[&F];
2201 if (CachedKernel)
2202 return *CachedKernel;
2203
2204 // TODO: We should use an AA to create an (optimistic and callback
2205 // call-aware) call graph. For now we stick to simple patterns that
2206 // are less powerful, basically the worst fixpoint.
2207 if (isOpenMPKernel(F)) {
2208 CachedKernel = Kernel(&F);
2209 return *CachedKernel;
2210 }
2211
2212 CachedKernel = nullptr;
2213 if (!F.hasLocalLinkage()) {
2214
2215 // See https://openmp.llvm.org/remarks/OptimizationRemarks.html
2216 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
2217 return ORA << "Potentially unknown OpenMP target region caller.";
2218 };
2220
2221 return nullptr;
2222 }
2223 }
2224
2225 auto GetUniqueKernelForUse = [&](const Use &U) -> Kernel {
2226 if (auto *Cmp = dyn_cast<ICmpInst>(U.getUser())) {
2227 // Allow use in equality comparisons.
2228 if (Cmp->isEquality())
2229 return getUniqueKernelFor(*Cmp);
2230 return nullptr;
2231 }
2232 if (auto *CB = dyn_cast<CallBase>(U.getUser())) {
2233 // Allow direct calls.
2234 if (CB->isCallee(&U))
2235 return getUniqueKernelFor(*CB);
2236
2237 OMPInformationCache::RuntimeFunctionInfo &KernelParallelRFI =
2238 OMPInfoCache.RFIs[OMPRTL___kmpc_parallel_60];
2239 // Allow the use in __kmpc_parallel_60 calls.
2240 if (OpenMPOpt::getCallIfRegularCall(*U.getUser(), &KernelParallelRFI))
2241 return getUniqueKernelFor(*CB);
2242 return nullptr;
2243 }
2244 // Disallow every other use.
2245 return nullptr;
2246 };
2247
2248 // TODO: In the future we want to track more than just a unique kernel.
2249 SmallPtrSet<Kernel, 2> PotentialKernels;
2250 OMPInformationCache::foreachUse(F, [&](const Use &U) {
2251 PotentialKernels.insert(GetUniqueKernelForUse(U));
2252 });
2253
2254 Kernel K = nullptr;
2255 if (PotentialKernels.size() == 1)
2256 K = *PotentialKernels.begin();
2257
2258 // Cache the result.
2259 UniqueKernelMap[&F] = K;
2260
2261 return K;
2262}
2263
2264bool OpenMPOpt::rewriteDeviceCodeStateMachine() {
2265 OMPInformationCache::RuntimeFunctionInfo &KernelParallelRFI =
2266 OMPInfoCache.RFIs[OMPRTL___kmpc_parallel_60];
2267
2268 bool Changed = false;
2269 if (!KernelParallelRFI)
2270 return Changed;
2271
2272 // If we have disabled state machine changes, exit
2274 return Changed;
2275
2276 for (Function *F : SCC) {
2277
2278 // Check if the function is a use in a __kmpc_parallel_60 call at
2279 // all.
2280 bool UnknownUse = false;
2281 bool KernelParallelUse = false;
2282 unsigned NumDirectCalls = 0;
2283
2284 SmallVector<Use *, 2> ToBeReplacedStateMachineUses;
2285 OMPInformationCache::foreachUse(*F, [&](Use &U) {
2286 if (auto *CB = dyn_cast<CallBase>(U.getUser()))
2287 if (CB->isCallee(&U)) {
2288 ++NumDirectCalls;
2289 return;
2290 }
2291
2292 if (isa<ICmpInst>(U.getUser())) {
2293 ToBeReplacedStateMachineUses.push_back(&U);
2294 return;
2295 }
2296
2297 // Find wrapper functions that represent parallel kernels.
2298 CallInst *CI =
2299 OpenMPOpt::getCallIfRegularCall(*U.getUser(), &KernelParallelRFI);
2300 const unsigned int WrapperFunctionArgNo = 6;
2301 if (!KernelParallelUse && CI &&
2302 CI->getArgOperandNo(&U) == WrapperFunctionArgNo) {
2303 KernelParallelUse = true;
2304 ToBeReplacedStateMachineUses.push_back(&U);
2305 return;
2306 }
2307 UnknownUse = true;
2308 });
2309
2310 // Do not emit a remark if we haven't seen a __kmpc_parallel_60
2311 // use.
2312 if (!KernelParallelUse)
2313 continue;
2314
2315 // If this ever hits, we should investigate.
2316 // TODO: Checking the number of uses is not a necessary restriction and
2317 // should be lifted.
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.";
2324 };
2326 continue;
2327 }
2328
2329 // Even if we have __kmpc_parallel_60 calls, we (for now) give
2330 // up if the function is not called from a unique kernel.
2331 Kernel K = getUniqueKernelFor(*F);
2332 if (!K) {
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.";
2336 };
2338 continue;
2339 }
2340
2341 // We now know F is a parallel body function called only from the kernel K.
2342 // We also identified the state machine uses in which we replace the
2343 // function pointer by a new global symbol for identification purposes. This
2344 // ensures only direct calls to the function are left.
2345
2346 Module &M = *F->getParent();
2347 Type *Int8Ty = Type::getInt8Ty(M.getContext());
2348
2349 auto *ID = new GlobalVariable(
2350 M, Int8Ty, /* isConstant */ true, GlobalValue::PrivateLinkage,
2351 UndefValue::get(Int8Ty), F->getName() + ".ID");
2352
2353 for (Use *U : ToBeReplacedStateMachineUses)
2355 ID, U->get()->getType()));
2356
2357 ++NumOpenMPParallelRegionsReplacedInGPUStateMachine;
2358
2359 Changed = true;
2360 }
2361
2362 return Changed;
2363}
2364
2365bool OpenMPOpt::removeSPMDParallelWrappers() {
2366 // Nothing to clean up unless we SPMD-ized at least one kernel.
2367 if (OMPInfoCache.SPMDizedKernels.empty())
2368 return false;
2369
2370 OMPInformationCache::RuntimeFunctionInfo &KernelParallelRFI =
2371 OMPInfoCache.RFIs[OMPRTL___kmpc_parallel_60];
2372 if (!KernelParallelRFI || !KernelParallelRFI.Declaration)
2373 return false;
2374
2375 constexpr unsigned WrapperFunctionArgNo = 6;
2376 bool Changed = false;
2377 for (User *U : KernelParallelRFI.Declaration->users()) {
2378 auto *CI = dyn_cast<CallInst>(U);
2379 if (!CI || CI->getCalledOperand() != KernelParallelRFI.Declaration ||
2380 CI->arg_size() <= WrapperFunctionArgNo)
2381 continue;
2382
2383 Value *Wrapper = CI->getArgOperand(WrapperFunctionArgNo);
2385 continue;
2386
2387 // Only drop the wrapper for a parallel region reached from a single kernel
2388 // that we transformed to SPMD mode. A region also reachable from a
2389 // generic-mode kernel still needs its wrapper for that kernel's state
2390 // machine, and getUniqueKernelFor conservatively bails on such shared
2391 // regions. (Mirrors the unique-kernel requirement in
2392 // rewriteDeviceCodeStateMachine.)
2393 Kernel K = getUniqueKernelFor(*CI->getFunction());
2394 if (!K || !OMPInfoCache.SPMDizedKernels.contains(K))
2395 continue;
2396
2397 CI->setArgOperand(
2398 WrapperFunctionArgNo,
2400 Changed = true;
2401 }
2402
2403 return Changed;
2404}
2405
2406/// Abstract Attribute for tracking ICV values.
2407struct AAICVTracker : public StateWrapper<BooleanState, AbstractAttribute> {
2408 using Base = StateWrapper<BooleanState, AbstractAttribute>;
2409 AAICVTracker(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
2410
2411 /// Returns true if value is assumed to be tracked.
2412 bool isAssumedTracked() const { return getAssumed(); }
2413
2414 /// Returns true if value is known to be tracked.
2415 bool isKnownTracked() const { return getAssumed(); }
2416
2417 /// Create an abstract attribute biew for the position \p IRP.
2418 static AAICVTracker &createForPosition(const IRPosition &IRP, Attributor &A);
2419
2420 /// Return the value with which \p I can be replaced for specific \p ICV.
2421 virtual std::optional<Value *> getReplacementValue(InternalControlVar ICV,
2422 const Instruction *I,
2423 Attributor &A) const {
2424 return std::nullopt;
2425 }
2426
2427 /// Return an assumed unique ICV value if a single candidate is found. If
2428 /// there cannot be one, return a nullptr. If it is not clear yet, return
2429 /// std::nullopt.
2430 virtual std::optional<Value *>
2431 getUniqueReplacementValue(InternalControlVar ICV) const = 0;
2432
2433 // Currently only nthreads is being tracked.
2434 // this array will only grow with time.
2435 InternalControlVar TrackableICVs[1] = {ICV_nthreads};
2436
2437 StringRef getName() const override { return "AAICVTracker"; }
2438
2439 const char *getIdAddr() const override { return &ID; }
2440
2441 /// This function should return true if the type of the \p AA is AAICVTracker
2442 static bool classof(const AbstractAttribute *AA) {
2443 return (AA->getIdAddr() == &ID);
2444 }
2445
2446 static const char ID;
2447};
2448
2449struct AAICVTrackerFunction : public AAICVTracker {
2450 AAICVTrackerFunction(const IRPosition &IRP, Attributor &A)
2451 : AAICVTracker(IRP, A) {}
2452
2453 // FIXME: come up with better string.
2454 const std::string getAsStr(Attributor *) const override {
2455 return "ICVTrackerFunction";
2456 }
2457
2458 // FIXME: come up with some stats.
2459 void trackStatistics() const override {}
2460
2461 /// We don't manifest anything for this AA.
2462 ChangeStatus manifest(Attributor &A) override {
2463 return ChangeStatus::UNCHANGED;
2464 }
2465
2466 // Map of ICV to their values at specific program point.
2467 EnumeratedArray<DenseMap<Instruction *, Value *>, InternalControlVar,
2468 InternalControlVar::ICV___last>
2469 ICVReplacementValuesMap;
2470
2471 ChangeStatus updateImpl(Attributor &A) override {
2472 ChangeStatus HasChanged = ChangeStatus::UNCHANGED;
2473
2474 Function *F = getAnchorScope();
2475
2476 auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
2477
2478 for (InternalControlVar ICV : TrackableICVs) {
2479 auto &SetterRFI = OMPInfoCache.RFIs[OMPInfoCache.ICVs[ICV].Setter];
2480
2481 auto &ValuesMap = ICVReplacementValuesMap[ICV];
2482 auto TrackValues = [&](Use &U, Function &) {
2483 CallInst *CI = OpenMPOpt::getCallIfRegularCall(U);
2484 if (!CI)
2485 return false;
2486
2487 // FIXME: handle setters with more that 1 arguments.
2488 /// Track new value.
2489 if (ValuesMap.insert(std::make_pair(CI, CI->getArgOperand(0))).second)
2490 HasChanged = ChangeStatus::CHANGED;
2491
2492 return false;
2493 };
2494
2495 auto CallCheck = [&](Instruction &I) {
2496 std::optional<Value *> ReplVal = getValueForCall(A, I, ICV);
2497 if (ReplVal && ValuesMap.insert(std::make_pair(&I, *ReplVal)).second)
2498 HasChanged = ChangeStatus::CHANGED;
2499
2500 return true;
2501 };
2502
2503 // Track all changes of an ICV.
2504 SetterRFI.foreachUse(TrackValues, F);
2505
2506 bool UsedAssumedInformation = false;
2507 A.checkForAllInstructions(CallCheck, *this, {Instruction::Call},
2508 UsedAssumedInformation,
2509 /* CheckBBLivenessOnly */ true);
2510
2511 /// TODO: Figure out a way to avoid adding entry in
2512 /// ICVReplacementValuesMap
2513 Instruction *Entry = &F->getEntryBlock().front();
2514 if (HasChanged == ChangeStatus::CHANGED)
2515 ValuesMap.try_emplace(Entry);
2516 }
2517
2518 return HasChanged;
2519 }
2520
2521 /// Helper to check if \p I is a call and get the value for it if it is
2522 /// unique.
2523 std::optional<Value *> getValueForCall(Attributor &A, const Instruction &I,
2524 InternalControlVar &ICV) const {
2525
2526 const auto *CB = dyn_cast<CallBase>(&I);
2527 if (!CB || CB->hasFnAttr("no_openmp") ||
2528 CB->hasFnAttr("no_openmp_routines") ||
2529 CB->hasFnAttr("no_openmp_constructs"))
2530 return std::nullopt;
2531
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];
2535 Function *CalledFunction = CB->getCalledFunction();
2536
2537 // Indirect call, assume ICV changes.
2538 if (CalledFunction == nullptr)
2539 return 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);
2545
2546 return nullptr;
2547 }
2548
2549 // Since we don't know, assume it changes the ICV.
2550 if (CalledFunction->isDeclaration())
2551 return nullptr;
2552
2553 const auto *ICVTrackingAA = A.getAAFor<AAICVTracker>(
2554 *this, IRPosition::callsite_returned(*CB), DepClassTy::REQUIRED);
2555
2556 if (ICVTrackingAA->isAssumedTracked()) {
2557 std::optional<Value *> URV =
2558 ICVTrackingAA->getUniqueReplacementValue(ICV);
2559 if (!URV || (*URV && AA::isValidAtPosition(AA::ValueAndContext(**URV, I),
2560 OMPInfoCache)))
2561 return URV;
2562 }
2563
2564 // If we don't know, assume it changes.
2565 return nullptr;
2566 }
2567
2568 // We don't check unique value for a function, so return std::nullopt.
2569 std::optional<Value *>
2570 getUniqueReplacementValue(InternalControlVar ICV) const override {
2571 return std::nullopt;
2572 }
2573
2574 /// Return the value with which \p I can be replaced for specific \p ICV.
2575 std::optional<Value *> getReplacementValue(InternalControlVar ICV,
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);
2581
2583 SmallPtrSet<const Instruction *, 16> Visited;
2584 Worklist.push_back(I);
2585
2586 std::optional<Value *> ReplVal;
2587
2588 while (!Worklist.empty()) {
2589 const Instruction *CurrInst = Worklist.pop_back_val();
2590 if (!Visited.insert(CurrInst).second)
2591 continue;
2592
2593 const BasicBlock *CurrBB = CurrInst->getParent();
2594
2595 // Go up and look for all potential setters/calls that might change the
2596 // ICV.
2597 while ((CurrInst = CurrInst->getPrevNode())) {
2598 if (ValuesMap.count(CurrInst)) {
2599 std::optional<Value *> NewReplVal = ValuesMap.lookup(CurrInst);
2600 // Unknown value, track new.
2601 if (!ReplVal) {
2602 ReplVal = NewReplVal;
2603 break;
2604 }
2605
2606 // If we found a new value, we can't know the icv value anymore.
2607 if (NewReplVal)
2608 if (ReplVal != NewReplVal)
2609 return nullptr;
2610
2611 break;
2612 }
2613
2614 std::optional<Value *> NewReplVal = getValueForCall(A, *CurrInst, ICV);
2615 if (!NewReplVal)
2616 continue;
2617
2618 // Unknown value, track new.
2619 if (!ReplVal) {
2620 ReplVal = NewReplVal;
2621 break;
2622 }
2623
2624 // if (NewReplVal.hasValue())
2625 // We found a new value, we can't know the icv value anymore.
2626 if (ReplVal != NewReplVal)
2627 return nullptr;
2628 }
2629
2630 // If we are in the same BB and we have a value, we are done.
2631 if (CurrBB == I->getParent() && ReplVal)
2632 return ReplVal;
2633
2634 // Go through all predecessors and add terminators for analysis.
2635 for (const BasicBlock *Pred : predecessors(CurrBB))
2636 Worklist.push_back(Pred->getTerminator());
2637 }
2638
2639 return ReplVal;
2640 }
2641};
2642
2643struct AAICVTrackerFunctionReturned : AAICVTracker {
2644 AAICVTrackerFunctionReturned(const IRPosition &IRP, Attributor &A)
2645 : AAICVTracker(IRP, A) {}
2646
2647 // FIXME: come up with better string.
2648 const std::string getAsStr(Attributor *) const override {
2649 return "ICVTrackerFunctionReturned";
2650 }
2651
2652 // FIXME: come up with some stats.
2653 void trackStatistics() const override {}
2654
2655 /// We don't manifest anything for this AA.
2656 ChangeStatus manifest(Attributor &A) override {
2657 return ChangeStatus::UNCHANGED;
2658 }
2659
2660 // Map of ICV to their values at specific program point.
2661 EnumeratedArray<std::optional<Value *>, InternalControlVar,
2662 InternalControlVar::ICV___last>
2663 ICVReplacementValuesMap;
2664
2665 /// Return the value with which \p I can be replaced for specific \p ICV.
2666 std::optional<Value *>
2667 getUniqueReplacementValue(InternalControlVar ICV) const override {
2668 return ICVReplacementValuesMap[ICV];
2669 }
2670
2671 ChangeStatus updateImpl(Attributor &A) override {
2672 ChangeStatus Changed = ChangeStatus::UNCHANGED;
2673 const auto *ICVTrackingAA = A.getAAFor<AAICVTracker>(
2674 *this, IRPosition::function(*getAnchorScope()), DepClassTy::REQUIRED);
2675
2676 if (!ICVTrackingAA->isAssumedTracked())
2677 return indicatePessimisticFixpoint();
2678
2679 for (InternalControlVar ICV : TrackableICVs) {
2680 std::optional<Value *> &ReplVal = ICVReplacementValuesMap[ICV];
2681 std::optional<Value *> UniqueICVValue;
2682
2683 auto CheckReturnInst = [&](Instruction &I) {
2684 std::optional<Value *> NewReplVal =
2685 ICVTrackingAA->getReplacementValue(ICV, &I, A);
2686
2687 // If we found a second ICV value there is no unique returned value.
2688 if (UniqueICVValue && UniqueICVValue != NewReplVal)
2689 return false;
2690
2691 UniqueICVValue = NewReplVal;
2692
2693 return true;
2694 };
2695
2696 bool UsedAssumedInformation = false;
2697 if (!A.checkForAllInstructions(CheckReturnInst, *this, {Instruction::Ret},
2698 UsedAssumedInformation,
2699 /* CheckBBLivenessOnly */ true))
2700 UniqueICVValue = nullptr;
2701
2702 if (UniqueICVValue == ReplVal)
2703 continue;
2704
2705 ReplVal = UniqueICVValue;
2706 Changed = ChangeStatus::CHANGED;
2707 }
2708
2709 return Changed;
2710 }
2711};
2712
2713struct AAICVTrackerCallSite : AAICVTracker {
2714 AAICVTrackerCallSite(const IRPosition &IRP, Attributor &A)
2715 : AAICVTracker(IRP, A) {}
2716
2717 void initialize(Attributor &A) override {
2718 assert(getAnchorScope() && "Expected anchor function");
2719
2720 // We only initialize this AA for getters, so we need to know which ICV it
2721 // gets.
2722 auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
2723 for (InternalControlVar ICV : TrackableICVs) {
2724 auto ICVInfo = OMPInfoCache.ICVs[ICV];
2725 auto &Getter = OMPInfoCache.RFIs[ICVInfo.Getter];
2726 if (Getter.Declaration == getAssociatedFunction()) {
2727 AssociatedICV = ICVInfo.Kind;
2728 return;
2729 }
2730 }
2731
2732 /// Unknown ICV.
2733 indicatePessimisticFixpoint();
2734 }
2735
2736 ChangeStatus manifest(Attributor &A) override {
2737 if (!ReplVal || !*ReplVal)
2738 return ChangeStatus::UNCHANGED;
2739
2740 A.changeAfterManifest(IRPosition::inst(*getCtxI()), **ReplVal);
2741 A.deleteAfterManifest(*getCtxI());
2742
2743 return ChangeStatus::CHANGED;
2744 }
2745
2746 // FIXME: come up with better string.
2747 const std::string getAsStr(Attributor *) const override {
2748 return "ICVTrackerCallSite";
2749 }
2750
2751 // FIXME: come up with some stats.
2752 void trackStatistics() const override {}
2753
2754 InternalControlVar AssociatedICV;
2755 std::optional<Value *> ReplVal;
2756
2757 ChangeStatus updateImpl(Attributor &A) override {
2758 const auto *ICVTrackingAA = A.getAAFor<AAICVTracker>(
2759 *this, IRPosition::function(*getAnchorScope()), DepClassTy::REQUIRED);
2760
2761 // We don't have any information, so we assume it changes the ICV.
2762 if (!ICVTrackingAA->isAssumedTracked())
2763 return indicatePessimisticFixpoint();
2764
2765 std::optional<Value *> NewReplVal =
2766 ICVTrackingAA->getReplacementValue(AssociatedICV, getCtxI(), A);
2767
2768 if (ReplVal == NewReplVal)
2769 return ChangeStatus::UNCHANGED;
2770
2771 ReplVal = NewReplVal;
2772 return ChangeStatus::CHANGED;
2773 }
2774
2775 // Return the value with which associated value can be replaced for specific
2776 // \p ICV.
2777 std::optional<Value *>
2778 getUniqueReplacementValue(InternalControlVar ICV) const override {
2779 return ReplVal;
2780 }
2781};
2782
2783struct AAICVTrackerCallSiteReturned : AAICVTracker {
2784 AAICVTrackerCallSiteReturned(const IRPosition &IRP, Attributor &A)
2785 : AAICVTracker(IRP, A) {}
2786
2787 // FIXME: come up with better string.
2788 const std::string getAsStr(Attributor *) const override {
2789 return "ICVTrackerCallSiteReturned";
2790 }
2791
2792 // FIXME: come up with some stats.
2793 void trackStatistics() const override {}
2794
2795 /// We don't manifest anything for this AA.
2796 ChangeStatus manifest(Attributor &A) override {
2797 return ChangeStatus::UNCHANGED;
2798 }
2799
2800 // Map of ICV to their values at specific program point.
2801 EnumeratedArray<std::optional<Value *>, InternalControlVar,
2802 InternalControlVar::ICV___last>
2803 ICVReplacementValuesMap;
2804
2805 /// Return the value with which associated value can be replaced for specific
2806 /// \p ICV.
2807 std::optional<Value *>
2808 getUniqueReplacementValue(InternalControlVar ICV) const override {
2809 return ICVReplacementValuesMap[ICV];
2810 }
2811
2812 ChangeStatus updateImpl(Attributor &A) override {
2813 ChangeStatus Changed = ChangeStatus::UNCHANGED;
2814 const auto *ICVTrackingAA = A.getAAFor<AAICVTracker>(
2815 *this, IRPosition::returned(*getAssociatedFunction()),
2816 DepClassTy::REQUIRED);
2817
2818 // We don't have any information, so we assume it changes the ICV.
2819 if (!ICVTrackingAA->isAssumedTracked())
2820 return indicatePessimisticFixpoint();
2821
2822 for (InternalControlVar ICV : TrackableICVs) {
2823 std::optional<Value *> &ReplVal = ICVReplacementValuesMap[ICV];
2824 std::optional<Value *> NewReplVal =
2825 ICVTrackingAA->getUniqueReplacementValue(ICV);
2826
2827 if (ReplVal == NewReplVal)
2828 continue;
2829
2830 ReplVal = NewReplVal;
2831 Changed = ChangeStatus::CHANGED;
2832 }
2833 return Changed;
2834 }
2835};
2836
2837/// Determines if \p BB exits the function unconditionally itself or reaches a
2838/// block that does through only unique successors.
2839static bool hasFunctionEndAsUniqueSuccessor(const BasicBlock *BB) {
2840 if (succ_empty(BB))
2841 return true;
2842 const BasicBlock *const Successor = BB->getUniqueSuccessor();
2843 if (!Successor)
2844 return false;
2845 return hasFunctionEndAsUniqueSuccessor(Successor);
2846}
2847
2848struct AAExecutionDomainFunction : public AAExecutionDomain {
2849 AAExecutionDomainFunction(const IRPosition &IRP, Attributor &A)
2850 : AAExecutionDomain(IRP, A) {}
2851
2852 ~AAExecutionDomainFunction() override { delete RPOT; }
2853
2854 void initialize(Attributor &A) override {
2855 Function *F = getAnchorScope();
2856 assert(F && "Expected anchor function");
2857 RPOT = new ReversePostOrderTraversal<Function *>(F);
2858 }
2859
2860 const std::string getAsStr(Attributor *) const override {
2861 unsigned TotalBlocks = 0, InitialThreadBlocks = 0, AlignedBlocks = 0;
2862 for (auto &It : BEDMap) {
2863 if (!It.getFirst())
2864 continue;
2865 TotalBlocks++;
2866 InitialThreadBlocks += It.getSecond().IsExecutedByInitialThreadOnly;
2867 AlignedBlocks += It.getSecond().IsReachedFromAlignedBarrierOnly &&
2868 It.getSecond().IsReachingAlignedBarrierOnly;
2869 }
2870 return "[AAExecutionDomain] " + std::to_string(InitialThreadBlocks) + "/" +
2871 std::to_string(AlignedBlocks) + " of " +
2872 std::to_string(TotalBlocks) +
2873 " executed by initial thread / aligned";
2874 }
2875
2876 void trackStatistics() const override {}
2877
2878 ChangeStatus manifest(Attributor &A) override {
2879 LLVM_DEBUG({
2880 for (const BasicBlock &BB : *getAnchorScope()) {
2881 if (!isExecutedByInitialThreadOnly(BB))
2882 continue;
2883 dbgs() << TAG << " Basic block @" << getAnchorScope()->getName() << " "
2884 << BB.getName() << " is executed by a single thread.\n";
2885 }
2886 });
2887
2888 ChangeStatus Changed = ChangeStatus::UNCHANGED;
2889
2891 return Changed;
2892
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)
2898 return;
2899 if (!ED.EncounteredAssumes.empty() && !A.isModulePass())
2900 return;
2901
2902 // We can remove this barrier, if it is one, or aligned barriers reaching
2903 // the kernel end (if CB is nullptr). Aligned barriers reaching the kernel
2904 // end should only be removed if the kernel end is their unique successor;
2905 // otherwise, they may have side-effects that aren't accounted for in the
2906 // kernel end in their other successors. If those barriers have other
2907 // barriers reaching them, those can be transitively removed as well as
2908 // long as the kernel end is also their unique successor.
2909 if (CB) {
2910 DeletedBarriers.insert(CB);
2911 A.deleteAfterManifest(*CB);
2912 ++NumBarriersEliminated;
2913 Changed = ChangeStatus::CHANGED;
2914 } else if (!ED.AlignedBarriers.empty()) {
2915 Changed = ChangeStatus::CHANGED;
2916 SmallVector<CallBase *> Worklist(ED.AlignedBarriers.begin(),
2917 ED.AlignedBarriers.end());
2918 SmallSetVector<CallBase *, 16> Visited;
2919 while (!Worklist.empty()) {
2920 CallBase *LastCB = Worklist.pop_back_val();
2921 if (!Visited.insert(LastCB))
2922 continue;
2923 if (LastCB->getFunction() != getAnchorScope())
2924 continue;
2925 if (!hasFunctionEndAsUniqueSuccessor(LastCB->getParent()))
2926 continue;
2927 if (!DeletedBarriers.count(LastCB)) {
2928 ++NumBarriersEliminated;
2929 A.deleteAfterManifest(*LastCB);
2930 continue;
2931 }
2932 // The final aligned barrier (LastCB) reaching the kernel end was
2933 // removed already. This means we can go one step further and remove
2934 // the barriers encoutered last before (LastCB).
2935 const ExecutionDomainTy &LastED = CEDMap[{LastCB, PRE}];
2936 Worklist.append(LastED.AlignedBarriers.begin(),
2937 LastED.AlignedBarriers.end());
2938 }
2939 }
2940
2941 // If we actually eliminated a barrier we need to eliminate the associated
2942 // llvm.assumes as well to avoid creating UB.
2943 if (!ED.EncounteredAssumes.empty() && (CB || !ED.AlignedBarriers.empty()))
2944 for (auto *AssumeCB : ED.EncounteredAssumes)
2945 A.deleteAfterManifest(*AssumeCB);
2946 };
2947
2948 for (auto *CB : AlignedBarriers)
2949 HandleAlignedBarrier(CB);
2950
2951 // Handle the "kernel end barrier" for kernels too.
2952 if (omp::isOpenMPKernel(*getAnchorScope()))
2953 HandleAlignedBarrier(nullptr);
2954
2955 return Changed;
2956 }
2957
2958 bool isNoOpFence(const FenceInst &FI) const override {
2959 return getState().isValidState() && !NonNoOpFences.count(&FI);
2960 }
2961
2962 /// Merge barrier and assumption information from \p PredED into the successor
2963 /// \p ED.
2964 void
2965 mergeInPredecessorBarriersAndAssumptions(Attributor &A, ExecutionDomainTy &ED,
2966 const ExecutionDomainTy &PredED);
2967
2968 /// Merge all information from \p PredED into the successor \p ED. If
2969 /// \p InitialEdgeOnly is set, only the initial edge will enter the block
2970 /// represented by \p ED from this predecessor.
2971 bool mergeInPredecessor(Attributor &A, ExecutionDomainTy &ED,
2972 const ExecutionDomainTy &PredED,
2973 bool InitialEdgeOnly = false);
2974
2975 /// Accumulate information for the entry block in \p EntryBBED.
2976 bool handleCallees(Attributor &A, ExecutionDomainTy &EntryBBED);
2977
2978 ChangeStatus updateImpl(Attributor &A) override;
2979
2980 /// Query interface, see AAExecutionDomain
2981 ///{
2982 bool isExecutedByInitialThreadOnly(const BasicBlock &BB) const override {
2983 if (!isValidState())
2984 return false;
2985 assert(BB.getParent() == getAnchorScope() && "Block is out of scope!");
2986 return BEDMap.lookup(&BB).IsExecutedByInitialThreadOnly;
2987 }
2988
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())
2994 return false;
2995
2996 bool ForwardIsOk = true;
2997 const Instruction *CurI;
2998
2999 // Check forward until a call or the block end is reached.
3000 CurI = &I;
3001 do {
3002 auto *CB = dyn_cast<CallBase>(CurI);
3003 if (!CB)
3004 continue;
3005 if (CB != &I && AlignedBarriers.contains(const_cast<CallBase *>(CB)))
3006 return true;
3007 const auto &It = CEDMap.find({CB, PRE});
3008 if (It == CEDMap.end())
3009 continue;
3010 if (!It->getSecond().IsReachingAlignedBarrierOnly)
3011 ForwardIsOk = false;
3012 break;
3013 } while ((CurI = CurI->getNextNode()));
3014
3015 if (!CurI && !BEDMap.lookup(I.getParent()).IsReachingAlignedBarrierOnly)
3016 ForwardIsOk = false;
3017
3018 // Check backward until a call or the block beginning is reached.
3019 CurI = &I;
3020 do {
3021 auto *CB = dyn_cast<CallBase>(CurI);
3022 if (!CB)
3023 continue;
3024 if (CB != &I && AlignedBarriers.contains(const_cast<CallBase *>(CB)))
3025 return true;
3026 const auto &It = CEDMap.find({CB, POST});
3027 if (It == CEDMap.end())
3028 continue;
3029 if (It->getSecond().IsReachedFromAlignedBarrierOnly)
3030 break;
3031 return false;
3032 } while ((CurI = CurI->getPrevNode()));
3033
3034 // Delayed decision on the forward pass to allow aligned barrier detection
3035 // in the backwards traversal.
3036 if (!ForwardIsOk)
3037 return false;
3038
3039 if (!CurI) {
3040 const BasicBlock *BB = I.getParent();
3041 if (BB == &BB->getParent()->getEntryBlock())
3042 return BEDMap.lookup(nullptr).IsReachedFromAlignedBarrierOnly;
3043 if (!llvm::all_of(predecessors(BB), [&](const BasicBlock *PredBB) {
3044 return BEDMap.lookup(PredBB).IsReachedFromAlignedBarrierOnly;
3045 })) {
3046 return false;
3047 }
3048 }
3049
3050 // On neither traversal we found a anything but aligned barriers.
3051 return true;
3052 }
3053
3054 ExecutionDomainTy getExecutionDomain(const BasicBlock &BB) const override {
3055 assert(isValidState() &&
3056 "No request should be made against an invalid state!");
3057 return BEDMap.lookup(&BB);
3058 }
3059 std::pair<ExecutionDomainTy, ExecutionDomainTy>
3060 getExecutionDomain(const CallBase &CB) const override {
3061 assert(isValidState() &&
3062 "No request should be made against an invalid state!");
3063 return {CEDMap.lookup({&CB, PRE}), CEDMap.lookup({&CB, POST})};
3064 }
3065 ExecutionDomainTy getFunctionExecutionDomain() const override {
3066 assert(isValidState() &&
3067 "No request should be made against an invalid state!");
3068 return InterProceduralED;
3069 }
3070 ///}
3071
3072 // Check if the edge into the successor block contains a condition that only
3073 // lets the main thread execute it.
3074 static bool isInitialThreadOnlyEdge(Attributor &A, CondBrInst *Edge,
3075 BasicBlock &SuccessorBB) {
3076 if (!Edge)
3077 return false;
3078 if (Edge->getSuccessor(0) != &SuccessorBB)
3079 return false;
3080
3081 auto *Cmp = dyn_cast<CmpInst>(Edge->getCondition());
3082 if (!Cmp || !Cmp->isTrueWhenEqual() || !Cmp->isEquality())
3083 return false;
3084
3085 ConstantInt *C = dyn_cast<ConstantInt>(Cmp->getOperand(1));
3086 if (!C)
3087 return false;
3088
3089 // Match: -1 == __kmpc_target_init (for non-SPMD kernels only!)
3090 if (C->isAllOnesValue()) {
3091 auto *CB = dyn_cast<CallBase>(Cmp->getOperand(0));
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;
3095 if (!CB)
3096 return false;
3097 ConstantStruct *KernelEnvC =
3099 ConstantInt *ExecModeC =
3100 KernelInfo::getExecModeFromKernelEnvironment(KernelEnvC);
3101 return ExecModeC->getSExtValue() & OMP_TGT_EXEC_MODE_GENERIC;
3102 }
3103
3104 if (C->isZero()) {
3105 // Match: 0 == llvm.nvvm.read.ptx.sreg.tid.x()
3106 if (auto *II = dyn_cast<IntrinsicInst>(Cmp->getOperand(0)))
3107 if (II->getIntrinsicID() == Intrinsic::nvvm_read_ptx_sreg_tid_x)
3108 return true;
3109
3110 // Match: 0 == llvm.amdgcn.workitem.id.x()
3111 if (auto *II = dyn_cast<IntrinsicInst>(Cmp->getOperand(0)))
3112 if (II->getIntrinsicID() == Intrinsic::amdgcn_workitem_id_x)
3113 return true;
3114 }
3115
3116 return false;
3117 };
3118
3119 /// Mapping containing information about the function for other AAs.
3120 ExecutionDomainTy InterProceduralED;
3121
3122 enum Direction { PRE = 0, POST = 1 };
3123 /// Mapping containing information per block.
3124 DenseMap<const BasicBlock *, ExecutionDomainTy> BEDMap;
3125 DenseMap<PointerIntPair<const CallBase *, 1, Direction>, ExecutionDomainTy>
3126 CEDMap;
3127 SmallSetVector<CallBase *, 16> AlignedBarriers;
3128
3129 ReversePostOrderTraversal<Function *> *RPOT = nullptr;
3130
3131 /// Set \p R to \V and report true if that changed \p R.
3132 static bool setAndRecord(bool &R, bool V) {
3133 bool Eq = (R == V);
3134 R = V;
3135 return !Eq;
3136 }
3137
3138 /// Collection of fences known to be non-no-opt. All fences not in this set
3139 /// can be assumed no-opt.
3140 SmallPtrSet<const FenceInst *, 8> NonNoOpFences;
3141};
3142
3143void AAExecutionDomainFunction::mergeInPredecessorBarriersAndAssumptions(
3144 Attributor &A, ExecutionDomainTy &ED, const ExecutionDomainTy &PredED) {
3145 for (auto *EA : PredED.EncounteredAssumes)
3146 ED.addAssumeInst(A, *EA);
3147
3148 for (auto *AB : PredED.AlignedBarriers)
3149 ED.addAlignedBarrier(A, *AB);
3150}
3151
3152bool AAExecutionDomainFunction::mergeInPredecessor(
3153 Attributor &A, ExecutionDomainTy &ED, const ExecutionDomainTy &PredED,
3154 bool InitialEdgeOnly) {
3155
3156 bool Changed = false;
3157 Changed |=
3158 setAndRecord(ED.IsExecutedByInitialThreadOnly,
3159 InitialEdgeOnly || (PredED.IsExecutedByInitialThreadOnly &&
3160 ED.IsExecutedByInitialThreadOnly));
3161
3162 Changed |= setAndRecord(ED.IsReachedFromAlignedBarrierOnly,
3163 ED.IsReachedFromAlignedBarrierOnly &&
3164 PredED.IsReachedFromAlignedBarrierOnly);
3165 Changed |= setAndRecord(ED.EncounteredNonLocalSideEffect,
3166 ED.EncounteredNonLocalSideEffect |
3167 PredED.EncounteredNonLocalSideEffect);
3168 // Do not track assumptions and barriers as part of Changed.
3169 if (ED.IsReachedFromAlignedBarrierOnly)
3170 mergeInPredecessorBarriersAndAssumptions(A, ED, PredED);
3171 else
3172 ED.clearAssumeInstAndAlignedBarriers();
3173 return Changed;
3174}
3175
3176bool AAExecutionDomainFunction::handleCallees(Attributor &A,
3177 ExecutionDomainTy &EntryBBED) {
3179 auto PredForCallSite = [&](AbstractCallSite ACS) {
3180 const auto *EDAA = A.getAAFor<AAExecutionDomain>(
3181 *this, IRPosition::function(*ACS.getInstruction()->getFunction()),
3182 DepClassTy::OPTIONAL);
3183 if (!EDAA || !EDAA->getState().isValidState())
3184 return false;
3185 CallSiteEDs.emplace_back(
3186 EDAA->getExecutionDomain(*cast<CallBase>(ACS.getInstruction())));
3187 return true;
3188 };
3189
3190 ExecutionDomainTy ExitED;
3191 bool AllCallSitesKnown;
3192 if (A.checkForAllCallSites(PredForCallSite, *this,
3193 /* RequiresAllCallSites */ true,
3194 AllCallSitesKnown)) {
3195 for (const auto &[CSInED, CSOutED] : CallSiteEDs) {
3196 mergeInPredecessor(A, EntryBBED, CSInED);
3197 ExitED.IsReachingAlignedBarrierOnly &=
3198 CSOutED.IsReachingAlignedBarrierOnly;
3199 }
3200
3201 } else {
3202 // We could not find all predecessors, so this is either a kernel or a
3203 // function with external linkage (or with some other weird uses).
3204 if (omp::isOpenMPKernel(*getAnchorScope())) {
3205 EntryBBED.IsExecutedByInitialThreadOnly = false;
3206 EntryBBED.IsReachedFromAlignedBarrierOnly = true;
3207 EntryBBED.EncounteredNonLocalSideEffect = false;
3208 ExitED.IsReachingAlignedBarrierOnly = false;
3209 } else {
3210 EntryBBED.IsExecutedByInitialThreadOnly = false;
3211 EntryBBED.IsReachedFromAlignedBarrierOnly = false;
3212 EntryBBED.EncounteredNonLocalSideEffect = true;
3213 ExitED.IsReachingAlignedBarrierOnly = false;
3214 }
3215 }
3216
3217 bool Changed = 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);
3227 return Changed;
3228}
3229
3230ChangeStatus AAExecutionDomainFunction::updateImpl(Attributor &A) {
3231
3232 bool Changed = false;
3233
3234 // Helper to deal with an aligned barrier encountered during the forward
3235 // traversal. \p CB is the aligned barrier, \p ED is the execution domain when
3236 // it was encountered.
3237 auto HandleAlignedBarrier = [&](CallBase &CB, ExecutionDomainTy &ED) {
3238 Changed |= AlignedBarriers.insert(&CB);
3239 // First, update the barrier ED kept in the separate CEDMap.
3240 auto &CallInED = CEDMap[{&CB, PRE}];
3241 Changed |= mergeInPredecessor(A, CallInED, ED);
3242 CallInED.IsReachingAlignedBarrierOnly = true;
3243 // Next adjust the ED we use for the traversal.
3244 ED.EncounteredNonLocalSideEffect = false;
3245 ED.IsReachedFromAlignedBarrierOnly = true;
3246 // Aligned barrier collection has to come last.
3247 ED.clearAssumeInstAndAlignedBarriers();
3248 ED.addAlignedBarrier(A, CB);
3249 auto &CallOutED = CEDMap[{&CB, POST}];
3250 Changed |= mergeInPredecessor(A, CallOutED, ED);
3251 };
3252
3253 auto *LivenessAA =
3254 A.getAAFor<AAIsDead>(*this, getIRPosition(), DepClassTy::OPTIONAL);
3255
3256 Function *F = getAnchorScope();
3257 BasicBlock &EntryBB = F->getEntryBlock();
3258 bool IsKernel = omp::isOpenMPKernel(*F);
3259
3260 SmallVector<Instruction *> SyncInstWorklist;
3261 for (auto &RIt : *RPOT) {
3262 BasicBlock &BB = *RIt;
3263
3264 bool IsEntryBB = &BB == &EntryBB;
3265 // TODO: We use local reasoning since we don't have a divergence analysis
3266 // running as well. We could basically allow uniform branches here.
3267 bool AlignedBarrierLastInBlock = IsEntryBB && IsKernel;
3268 bool IsExplicitlyAligned = IsEntryBB && IsKernel;
3269 ExecutionDomainTy ED;
3270 // Propagate "incoming edges" into information about this block.
3271 if (IsEntryBB) {
3272 Changed |= handleCallees(A, ED);
3273 } else {
3274 // For live non-entry blocks we only propagate
3275 // information via live edges.
3276 if (LivenessAA && LivenessAA->isAssumedDead(&BB))
3277 continue;
3278
3279 for (auto *PredBB : predecessors(&BB)) {
3280 if (LivenessAA && LivenessAA->isEdgeDead(PredBB, &BB))
3281 continue;
3282 bool InitialEdgeOnly = isInitialThreadOnlyEdge(
3283 A, dyn_cast<CondBrInst>(PredBB->getTerminator()), BB);
3284 mergeInPredecessor(A, ED, BEDMap[PredBB], InitialEdgeOnly);
3285 }
3286 }
3287
3288 // Now we traverse the block, accumulate effects in ED and attach
3289 // information to calls.
3290 for (Instruction &I : BB) {
3291 bool UsedAssumedInformation;
3292 if (A.isAssumedDead(I, *this, LivenessAA, UsedAssumedInformation,
3293 /* CheckBBLivenessOnly */ false, DepClassTy::OPTIONAL,
3294 /* CheckForDeadStore */ true))
3295 continue;
3296
3297 // Asummes and "assume-like" (dbg, lifetime, ...) are handled first, the
3298 // former is collected the latter is ignored.
3299 if (auto *II = dyn_cast<IntrinsicInst>(&I)) {
3300 if (auto *AI = dyn_cast_or_null<AssumeInst>(II)) {
3301 ED.addAssumeInst(A, *AI);
3302 continue;
3303 }
3304 // TODO: Should we also collect and delete lifetime markers?
3305 if (II->isAssumeLikeIntrinsic())
3306 continue;
3307 }
3308
3309 if (auto *FI = dyn_cast<FenceInst>(&I)) {
3310 if (!ED.EncounteredNonLocalSideEffect) {
3311 // An aligned fence without non-local side-effects is a no-op.
3312 if (ED.IsReachedFromAlignedBarrierOnly)
3313 continue;
3314 // A non-aligned fence without non-local side-effects is a no-op
3315 // if the ordering only publishes non-local side-effects (or less).
3316 switch (FI->getOrdering()) {
3317 case AtomicOrdering::NotAtomic:
3318 continue;
3319 case AtomicOrdering::Unordered:
3320 continue;
3321 case AtomicOrdering::Monotonic:
3322 continue;
3323 case AtomicOrdering::Acquire:
3324 break;
3325 case AtomicOrdering::Release:
3326 continue;
3327 case AtomicOrdering::AcquireRelease:
3328 break;
3329 case AtomicOrdering::SequentiallyConsistent:
3330 break;
3331 };
3332 }
3333 NonNoOpFences.insert(FI);
3334 }
3335
3336 auto *CB = dyn_cast<CallBase>(&I);
3337 bool IsNoSync = AA::isNoSyncInst(A, I, *this);
3338 bool IsAlignedBarrier =
3339 !IsNoSync && CB &&
3340 AANoSync::isAlignedBarrier(*CB, AlignedBarrierLastInBlock);
3341
3342 AlignedBarrierLastInBlock &= IsNoSync;
3343 IsExplicitlyAligned &= IsNoSync;
3344
3345 // Next we check for calls. Aligned barriers are handled
3346 // explicitly, everything else is kept for the backward traversal and will
3347 // also affect our state.
3348 if (CB) {
3349 if (IsAlignedBarrier) {
3350 HandleAlignedBarrier(*CB, ED);
3351 AlignedBarrierLastInBlock = true;
3352 IsExplicitlyAligned = true;
3353 continue;
3354 }
3355
3356 // Check the pointer(s) of a memory intrinsic explicitly.
3357 if (isa<MemIntrinsic>(&I)) {
3358 if (!ED.EncounteredNonLocalSideEffect &&
3360 ED.EncounteredNonLocalSideEffect = true;
3361 if (!IsNoSync) {
3362 ED.IsReachedFromAlignedBarrierOnly = false;
3363 SyncInstWorklist.push_back(&I);
3364 }
3365 continue;
3366 }
3367
3368 // Record how we entered the call, then accumulate the effect of the
3369 // call in ED for potential use by the callee.
3370 auto &CallInED = CEDMap[{CB, PRE}];
3371 Changed |= mergeInPredecessor(A, CallInED, ED);
3372
3373 // If we have a sync-definition we can check if it starts/ends in an
3374 // aligned barrier. If we are unsure we assume any sync breaks
3375 // alignment.
3377 if (!IsNoSync && Callee && !Callee->isDeclaration()) {
3378 const auto *EDAA = A.getAAFor<AAExecutionDomain>(
3379 *this, IRPosition::function(*Callee), DepClassTy::OPTIONAL);
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;
3388 else
3389 ED.EncounteredNonLocalSideEffect =
3390 CalleeED.EncounteredNonLocalSideEffect;
3391 if (!CalleeED.IsReachingAlignedBarrierOnly) {
3392 Changed |=
3393 setAndRecord(CallInED.IsReachingAlignedBarrierOnly, false);
3394 SyncInstWorklist.push_back(&I);
3395 }
3396 if (CalleeED.IsReachedFromAlignedBarrierOnly)
3397 mergeInPredecessorBarriersAndAssumptions(A, ED, CalleeED);
3398 auto &CallOutED = CEDMap[{CB, POST}];
3399 Changed |= mergeInPredecessor(A, CallOutED, ED);
3400 continue;
3401 }
3402 }
3403 if (!IsNoSync) {
3404 ED.IsReachedFromAlignedBarrierOnly = false;
3405 Changed |= setAndRecord(CallInED.IsReachingAlignedBarrierOnly, false);
3406 SyncInstWorklist.push_back(&I);
3407 }
3408 AlignedBarrierLastInBlock &= ED.IsReachedFromAlignedBarrierOnly;
3409 ED.EncounteredNonLocalSideEffect |= !CB->doesNotAccessMemory();
3410 auto &CallOutED = CEDMap[{CB, POST}];
3411 Changed |= mergeInPredecessor(A, CallOutED, ED);
3412 }
3413
3414 if (!I.mayHaveSideEffects() && !I.mayReadFromMemory())
3415 continue;
3416
3417 // If we have a callee we try to use fine-grained information to
3418 // determine local side-effects.
3419 if (CB) {
3420 const auto *MemAA = A.getAAFor<AAMemoryLocation>(
3421 *this, IRPosition::callsite_function(*CB), DepClassTy::OPTIONAL);
3422
3423 auto AccessPred = [&](const Instruction *I, const Value *Ptr,
3426 return !AA::isPotentiallyAffectedByBarrier(A, {Ptr}, *this, I);
3427 };
3428 if (MemAA && MemAA->getState().isValidState() &&
3429 MemAA->checkForAllAccessesToMemoryKind(
3431 continue;
3432 }
3433
3434 auto &InfoCache = A.getInfoCache();
3435 if (!I.mayHaveSideEffects() && InfoCache.isOnlyUsedByAssume(I))
3436 continue;
3437
3438 if (auto *LI = dyn_cast<LoadInst>(&I))
3439 if (LI->hasMetadata(LLVMContext::MD_invariant_load))
3440 continue;
3441
3442 if (!ED.EncounteredNonLocalSideEffect &&
3444 ED.EncounteredNonLocalSideEffect = true;
3445 }
3446
3447 bool IsEndAndNotReachingAlignedBarriersOnly = false;
3448 if (!isa<UnreachableInst>(BB.getTerminator()) &&
3449 !BB.getTerminator()->getNumSuccessors()) {
3450
3451 Changed |= mergeInPredecessor(A, InterProceduralED, ED);
3452
3453 auto &FnED = BEDMap[nullptr];
3454 if (IsKernel && !IsExplicitlyAligned)
3455 FnED.IsReachingAlignedBarrierOnly = false;
3456 Changed |= mergeInPredecessor(A, FnED, ED);
3457
3458 if (!FnED.IsReachingAlignedBarrierOnly) {
3459 IsEndAndNotReachingAlignedBarriersOnly = true;
3460 SyncInstWorklist.push_back(BB.getTerminator());
3461 auto &BBED = BEDMap[&BB];
3462 Changed |= setAndRecord(BBED.IsReachingAlignedBarrierOnly, false);
3463 }
3464 }
3465
3466 ExecutionDomainTy &StoredED = BEDMap[&BB];
3467 ED.IsReachingAlignedBarrierOnly = StoredED.IsReachingAlignedBarrierOnly &&
3468 !IsEndAndNotReachingAlignedBarriersOnly;
3469
3470 // Check if we computed anything different as part of the forward
3471 // traversal. We do not take assumptions and aligned barriers into account
3472 // as they do not influence the state we iterate. Backward traversal values
3473 // are handled later on.
3474 if (ED.IsExecutedByInitialThreadOnly !=
3475 StoredED.IsExecutedByInitialThreadOnly ||
3476 ED.IsReachedFromAlignedBarrierOnly !=
3477 StoredED.IsReachedFromAlignedBarrierOnly ||
3478 ED.EncounteredNonLocalSideEffect !=
3479 StoredED.EncounteredNonLocalSideEffect)
3480 Changed = true;
3481
3482 // Update the state with the new value.
3483 StoredED = std::move(ED);
3484 }
3485
3486 // Propagate (non-aligned) sync instruction effects backwards until the
3487 // entry is hit or an aligned barrier.
3488 SmallSetVector<BasicBlock *, 16> Visited;
3489 while (!SyncInstWorklist.empty()) {
3490 Instruction *SyncInst = SyncInstWorklist.pop_back_val();
3491 Instruction *CurInst = SyncInst;
3492 bool HitAlignedBarrierOrKnownEnd = false;
3493 while ((CurInst = CurInst->getPrevNode())) {
3494 auto *CB = dyn_cast<CallBase>(CurInst);
3495 if (!CB)
3496 continue;
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)
3503 break;
3504 Changed |= setAndRecord(CallInED.IsReachingAlignedBarrierOnly, false);
3505 }
3506 if (HitAlignedBarrierOrKnownEnd)
3507 continue;
3508 BasicBlock *SyncBB = SyncInst->getParent();
3509 for (auto *PredBB : predecessors(SyncBB)) {
3510 if (LivenessAA && LivenessAA->isEdgeDead(PredBB, SyncBB))
3511 continue;
3512 if (!Visited.insert(PredBB))
3513 continue;
3514 auto &PredED = BEDMap[PredBB];
3515 if (setAndRecord(PredED.IsReachingAlignedBarrierOnly, false)) {
3516 Changed = true;
3517 SyncInstWorklist.push_back(PredBB->getTerminator());
3518 }
3519 }
3520 if (SyncBB != &EntryBB)
3521 continue;
3522 Changed |=
3523 setAndRecord(InterProceduralED.IsReachingAlignedBarrierOnly, false);
3524 }
3525
3526 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
3527}
3528
3529/// Try to replace memory allocation calls called by a single thread with a
3530/// static buffer of shared memory.
3531struct AAHeapToShared : public StateWrapper<BooleanState, AbstractAttribute> {
3532 using Base = StateWrapper<BooleanState, AbstractAttribute>;
3533 AAHeapToShared(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
3534
3535 /// Create an abstract attribute view for the position \p IRP.
3536 static AAHeapToShared &createForPosition(const IRPosition &IRP,
3537 Attributor &A);
3538
3539 /// Returns true if HeapToShared conversion is assumed to be possible.
3540 virtual bool isAssumedHeapToShared(CallBase &CB) const = 0;
3541
3542 /// Returns true if HeapToShared conversion is assumed and the CB is a
3543 /// callsite to a free operation to be removed.
3544 virtual bool isAssumedHeapToSharedRemovedFree(CallBase &CB) const = 0;
3545
3546 StringRef getName() const override { return "AAHeapToShared"; }
3547
3548 const char *getIdAddr() const override { return &ID; }
3549
3550 /// This function should return true if the type of the \p AA is
3551 /// AAHeapToShared.
3552 static bool classof(const AbstractAttribute *AA) {
3553 return (AA->getIdAddr() == &ID);
3554 }
3555
3556 /// Unique ID (due to the unique address)
3557 static const char ID;
3558};
3559
3560struct AAHeapToSharedFunction : public AAHeapToShared {
3561 AAHeapToSharedFunction(const IRPosition &IRP, Attributor &A)
3562 : AAHeapToShared(IRP, A) {}
3563
3564 const std::string getAsStr(Attributor *) const override {
3565 return "[AAHeapToShared] " + std::to_string(MallocCalls.size()) +
3566 " malloc calls eligible.";
3567 }
3568
3569 void trackStatistics() const override {}
3570
3571 /// This functions finds free calls that will be removed by the
3572 /// HeapToShared transformation.
3573 void findPotentialRemovedFreeCalls(Attributor &A) {
3574 auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
3575 auto &FreeRFI = OMPInfoCache.RFIs[OMPRTL___kmpc_free_shared];
3576
3577 PotentialRemovedFreeCalls.clear();
3578 // Update free call users of found malloc calls.
3579 for (CallBase *CB : MallocCalls) {
3581 for (auto *U : CB->users()) {
3582 CallBase *C = dyn_cast<CallBase>(U);
3583 if (C && C->getCalledFunction() == FreeRFI.Declaration)
3584 FreeCalls.push_back(C);
3585 }
3586
3587 if (FreeCalls.size() != 1)
3588 continue;
3589
3590 PotentialRemovedFreeCalls.insert(FreeCalls.front());
3591 }
3592 }
3593
3594 void initialize(Attributor &A) override {
3596 indicatePessimisticFixpoint();
3597 return;
3598 }
3599
3600 auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
3601 auto &RFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
3602 if (!RFI.Declaration)
3603 return;
3604
3606 [](const IRPosition &, const AbstractAttribute *,
3607 bool &) -> std::optional<Value *> { return nullptr; };
3608
3609 Function *F = getAnchorScope();
3610 const OMPInformationCache::RuntimeFunctionInfo::UseVector *Uses =
3611 RFI.getUseVector(*F);
3612 if (!Uses)
3613 return;
3614
3615 for (Use *U : *Uses)
3616 if (CallBase *CB = dyn_cast<CallBase>(U->getUser())) {
3617 MallocCalls.insert(CB);
3618 A.registerSimplificationCallback(IRPosition::callsite_returned(*CB),
3619 SCB);
3620 }
3621
3622 findPotentialRemovedFreeCalls(A);
3623 }
3624
3625 bool isAssumedHeapToShared(CallBase &CB) const override {
3626 return isValidState() && MallocCalls.count(&CB);
3627 }
3628
3629 bool isAssumedHeapToSharedRemovedFree(CallBase &CB) const override {
3630 return isValidState() && PotentialRemovedFreeCalls.count(&CB);
3631 }
3632
3633 ChangeStatus manifest(Attributor &A) override {
3634 if (MallocCalls.empty())
3635 return ChangeStatus::UNCHANGED;
3636
3637 auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
3638 auto &FreeCall = OMPInfoCache.RFIs[OMPRTL___kmpc_free_shared];
3639
3640 Function *F = getAnchorScope();
3641 auto *HS = A.lookupAAFor<AAHeapToStack>(IRPosition::function(*F), this,
3642 DepClassTy::OPTIONAL);
3643
3644 ChangeStatus Changed = ChangeStatus::UNCHANGED;
3645 for (CallBase *CB : MallocCalls) {
3646 // Skip replacing this if HeapToStack has already claimed it.
3647 if (HS && HS->isAssumedHeapToStack(*CB))
3648 continue;
3649
3650 // Find the unique free call to remove it.
3652 for (auto *U : CB->users()) {
3653 CallBase *C = dyn_cast<CallBase>(U);
3654 if (C && C->getCalledFunction() == FreeCall.Declaration)
3655 FreeCalls.push_back(C);
3656 }
3657 if (FreeCalls.size() != 1)
3658 continue;
3659
3660 auto *AllocSize = cast<ConstantInt>(CB->getArgOperand(0));
3661
3662 if (AllocSize->getZExtValue() + SharedMemoryUsed > SharedMemoryLimit) {
3663 LLVM_DEBUG(dbgs() << TAG << "Cannot replace call " << *CB
3664 << " with shared memory."
3665 << " Shared memory usage is limited to "
3666 << SharedMemoryLimit << " bytes\n");
3667 continue;
3668 }
3669
3670 LLVM_DEBUG(dbgs() << TAG << "Replace globalization call " << *CB
3671 << " with " << AllocSize->getZExtValue()
3672 << " bytes of shared memory\n");
3673
3674 // Create a new shared memory buffer of the same size as the allocation
3675 // and replace all the uses of the original allocation with it.
3676 Module *M = CB->getModule();
3677 Type *Int8Ty = Type::getInt8Ty(M->getContext());
3678 Type *Int8ArrTy = ArrayType::get(Int8Ty, AllocSize->getZExtValue());
3679 auto *SharedMem = new GlobalVariable(
3680 *M, Int8ArrTy, /* IsConstant */ false, GlobalValue::InternalLinkage,
3681 PoisonValue::get(Int8ArrTy), CB->getName() + "_shared", nullptr,
3683 static_cast<unsigned>(AddressSpace::Shared));
3684 auto *NewBuffer = ConstantExpr::getPointerCast(
3685 SharedMem, PointerType::getUnqual(M->getContext()));
3686
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.";
3692 };
3693 A.emitRemark<OptimizationRemark>(CB, "OMP111", Remark);
3694
3695 MaybeAlign Alignment = CB->getRetAlign();
3696 assert(Alignment &&
3697 "HeapToShared on allocation without alignment attribute");
3698 SharedMem->setAlignment(*Alignment);
3699
3700 A.changeAfterManifest(IRPosition::callsite_returned(*CB), *NewBuffer);
3701 A.deleteAfterManifest(*CB);
3702 A.deleteAfterManifest(*FreeCalls.front());
3703
3704 SharedMemoryUsed += AllocSize->getZExtValue();
3705 NumBytesMovedToSharedMemory = SharedMemoryUsed;
3706 Changed = ChangeStatus::CHANGED;
3707 }
3708
3709 return Changed;
3710 }
3711
3712 ChangeStatus updateImpl(Attributor &A) override {
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;
3719
3720 Function *F = getAnchorScope();
3721
3722 auto NumMallocCalls = MallocCalls.size();
3723
3724 // Only consider malloc calls executed by a single thread with a constant.
3725 for (User *U : RFI.Declaration->users()) {
3726 if (CallBase *CB = dyn_cast<CallBase>(U)) {
3727 if (CB->getCaller() != F)
3728 continue;
3729 if (!MallocCalls.count(CB))
3730 continue;
3731 if (!isa<ConstantInt>(CB->getArgOperand(0))) {
3732 MallocCalls.remove(CB);
3733 continue;
3734 }
3735 const auto *ED = A.getAAFor<AAExecutionDomain>(
3736 *this, IRPosition::function(*F), DepClassTy::REQUIRED);
3737 if (!ED || !ED->isExecutedByInitialThreadOnly(*CB))
3738 MallocCalls.remove(CB);
3739 }
3740 }
3741
3742 findPotentialRemovedFreeCalls(A);
3743
3744 if (NumMallocCalls != MallocCalls.size())
3745 return ChangeStatus::CHANGED;
3746
3747 return ChangeStatus::UNCHANGED;
3748 }
3749
3750 /// Collection of all malloc calls in a function.
3751 SmallSetVector<CallBase *, 4> MallocCalls;
3752 /// Collection of potentially removed free calls in a function.
3753 SmallPtrSet<CallBase *, 4> PotentialRemovedFreeCalls;
3754 /// The total amount of shared memory that has been used for HeapToShared.
3755 unsigned SharedMemoryUsed = 0;
3756};
3757
3758struct AAKernelInfo : public StateWrapper<KernelInfoState, AbstractAttribute> {
3759 using Base = StateWrapper<KernelInfoState, AbstractAttribute>;
3760 AAKernelInfo(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
3761
3762 /// The callee value is tracked beyond a simple stripPointerCasts, so we allow
3763 /// unknown callees.
3764 static bool requiresCalleeForCallBase() { return false; }
3765
3766 /// Statistics are tracked as part of manifest for now.
3767 void trackStatistics() const override {}
3768
3769 const std::string getAsStr(Attributor *) const override {
3770 if (!isValidState())
3771 return "<invalid>";
3772 return std::string(SPMDCompatibilityTracker.isAssumed() ? "SPMD"
3773 : "generic") +
3774 std::string(SPMDCompatibilityTracker.isAtFixpoint() ? " [FIX]"
3775 : "") +
3776 std::string(" #PRs: ") +
3777 (ReachedKnownParallelRegions.isValidState()
3778 ? std::to_string(ReachedKnownParallelRegions.size())
3779 : "<invalid>") +
3780 ", #Unknown PRs: " +
3781 (ReachedUnknownParallelRegions.isValidState()
3782 ? std::to_string(ReachedUnknownParallelRegions.size())
3783 : "<invalid>") +
3784 ", #Reaching Kernels: " +
3785 (ReachingKernelEntries.isValidState()
3786 ? std::to_string(ReachingKernelEntries.size())
3787 : "<invalid>") +
3788 ", #ParLevels: " +
3789 (ParallelLevels.isValidState()
3790 ? std::to_string(ParallelLevels.size())
3791 : "<invalid>") +
3792 ", NestedPar: " + (NestedParallelism ? "yes" : "no");
3793 }
3794
3795 /// Create an abstract attribute biew for the position \p IRP.
3796 static AAKernelInfo &createForPosition(const IRPosition &IRP, Attributor &A);
3797
3798 StringRef getName() const override { return "AAKernelInfo"; }
3799
3800 const char *getIdAddr() const override { return &ID; }
3801
3802 /// This function should return true if the type of the \p AA is AAKernelInfo
3803 static bool classof(const AbstractAttribute *AA) {
3804 return (AA->getIdAddr() == &ID);
3805 }
3806
3807 static const char ID;
3808};
3809
3810// Fences stronger than a workgroup order memory the SPMD barrier does not.
3811static bool isStrictFence(const Instruction &I) {
3812 const auto *FI = dyn_cast<FenceInst>(&I);
3813 if (!FI)
3814 return false;
3816 if (SS == SyncScope::SingleThread)
3817 return false;
3818 if (SS == SyncScope::System)
3819 return true;
3820 std::optional<StringRef> Name = FI->getContext().getSyncScopeName(SS);
3821 if (!Name)
3822 return true;
3823 auto Parsed =
3825 if (!Parsed)
3826 return true;
3827 switch (Parsed->first) {
3828 case AtomicScope::Single:
3829 case AtomicScope::Wavefront:
3830 case AtomicScope::Workgroup:
3831 return false;
3832 case AtomicScope::Cluster:
3833 case AtomicScope::Device:
3834 case AtomicScope::System:
3835 return true;
3836 }
3837 return true;
3838}
3839
3840/// The function kernel info abstract attribute, basically, what can we say
3841/// about a function with regards to the KernelInfoState.
3842struct AAKernelInfoFunction : AAKernelInfo {
3843 AAKernelInfoFunction(const IRPosition &IRP, Attributor &A)
3844 : AAKernelInfo(IRP, A) {}
3845
3846 SmallPtrSet<Instruction *, 4> GuardedInstructions;
3847
3848 SmallPtrSetImpl<Instruction *> &getGuardedInstructions() {
3849 return GuardedInstructions;
3850 }
3851
3852 void setConfigurationOfKernelEnvironment(ConstantStruct *ConfigC) {
3854 KernelEnvC, ConfigC, {KernelInfo::ConfigurationIdx});
3855 assert(NewKernelEnvC && "Failed to create new kernel environment");
3856 KernelEnvC = cast<ConstantStruct>(NewKernelEnvC);
3857 }
3858
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)); \
3867 }
3868
3869 KERNEL_ENVIRONMENT_CONFIGURATION_SETTER(UseGenericStateMachine)
3870 KERNEL_ENVIRONMENT_CONFIGURATION_SETTER(MayUseNestedParallelism)
3876
3877#undef KERNEL_ENVIRONMENT_CONFIGURATION_SETTER
3878
3879 void initialize(Attributor &A) override {
3880 // This is a high-level transform that might change the constant arguments
3881 // of the init and dinit calls. We need to tell the Attributor about this
3882 // to avoid other parts using the current constant value for simpliication.
3883 auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
3884
3885 Function *Fn = getAnchorScope();
3886
3887 OMPInformationCache::RuntimeFunctionInfo &InitRFI =
3888 OMPInfoCache.RFIs[OMPRTL___kmpc_target_init];
3889 OMPInformationCache::RuntimeFunctionInfo &DeinitRFI =
3890 OMPInfoCache.RFIs[OMPRTL___kmpc_target_deinit];
3891
3892 // For kernels we perform more initialization work, first we find the init
3893 // and deinit calls.
3894 auto StoreCallBase = [](Use &U,
3895 OMPInformationCache::RuntimeFunctionInfo &RFI,
3896 CallBase *&Storage) {
3897 CallBase *CB = OpenMPOpt::getCallIfRegularCall(U, &RFI);
3898 assert(CB &&
3899 "Unexpected use of __kmpc_target_init or __kmpc_target_deinit!");
3900 assert(!Storage &&
3901 "Multiple uses of __kmpc_target_init or __kmpc_target_deinit!");
3902 Storage = CB;
3903 return false;
3904 };
3905 InitRFI.foreachUse(
3906 [&](Use &U, Function &) {
3907 StoreCallBase(U, InitRFI, KernelInitCB);
3908 return false;
3909 },
3910 Fn);
3911 DeinitRFI.foreachUse(
3912 [&](Use &U, Function &) {
3913 StoreCallBase(U, DeinitRFI, KernelDeinitCB);
3914 return false;
3915 },
3916 Fn);
3917
3918 // Ignore kernels without initializers such as global constructors.
3919 if (!KernelInitCB || !KernelDeinitCB)
3920 return;
3921
3922 // Add itself to the reaching kernel and set IsKernelEntry.
3923 ReachingKernelEntries.insert(Fn);
3924 IsKernelEntry = true;
3925
3926 KernelEnvC =
3928 GlobalVariable *KernelEnvGV =
3930
3932 KernelConfigurationSimplifyCB =
3933 [&](const GlobalVariable &GV, const AbstractAttribute *AA,
3934 bool &UsedAssumedInformation) -> std::optional<Constant *> {
3935 if (!isAtFixpoint()) {
3936 if (!AA)
3937 return nullptr;
3938 UsedAssumedInformation = true;
3939 A.recordDependence(*this, *AA, DepClassTy::OPTIONAL);
3940 }
3941 return KernelEnvC;
3942 };
3943
3944 A.registerGlobalVariableSimplificationCallback(
3945 *KernelEnvGV, KernelConfigurationSimplifyCB);
3946
3947 // We cannot change to SPMD mode if the runtime functions aren't availible.
3948 bool CanChangeToSPMD = OMPInfoCache.runtimeFnsAvailable(
3949 {OMPRTL___kmpc_get_hardware_thread_id_in_block,
3950 OMPRTL___kmpc_barrier_simple_spmd});
3951
3952 // Check if we know we are in SPMD-mode already.
3953 ConstantInt *ExecModeC =
3954 KernelInfo::getExecModeFromKernelEnvironment(KernelEnvC);
3955 ConstantInt *AssumedExecModeC = ConstantInt::get(
3956 ExecModeC->getIntegerType(),
3958 if (ExecModeC->getSExtValue() & OMP_TGT_EXEC_MODE_SPMD)
3959 SPMDCompatibilityTracker.indicateOptimisticFixpoint();
3960 else if (DisableOpenMPOptSPMDization || !CanChangeToSPMD)
3961 // This is a generic region but SPMDization is disabled so stop
3962 // tracking.
3963 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
3964 else
3965 setExecModeOfKernelEnvironment(AssumedExecModeC);
3966
3967 const Triple T(Fn->getParent()->getTargetTriple());
3968 auto *Int32Ty = Type::getInt32Ty(Fn->getContext());
3969 auto [MinThreads, MaxThreads] =
3971 if (MinThreads)
3972 setMinThreadsOfKernelEnvironment(ConstantInt::get(Int32Ty, MinThreads));
3973 if (MaxThreads)
3974 setMaxThreadsOfKernelEnvironment(ConstantInt::get(Int32Ty, MaxThreads));
3975 auto [MinTeams, MaxTeams] =
3977 if (MinTeams)
3978 setMinTeamsOfKernelEnvironment(ConstantInt::get(Int32Ty, MinTeams));
3979 if (MaxTeams)
3980 setMaxTeamsOfKernelEnvironment(ConstantInt::get(Int32Ty, MaxTeams));
3981
3982 ConstantInt *MayUseNestedParallelismC =
3983 KernelInfo::getMayUseNestedParallelismFromKernelEnvironment(KernelEnvC);
3984 ConstantInt *AssumedMayUseNestedParallelismC = ConstantInt::get(
3985 MayUseNestedParallelismC->getIntegerType(), NestedParallelism);
3986 setMayUseNestedParallelismOfKernelEnvironment(
3987 AssumedMayUseNestedParallelismC);
3988
3990 ConstantInt *UseGenericStateMachineC =
3991 KernelInfo::getUseGenericStateMachineFromKernelEnvironment(
3992 KernelEnvC);
3993 ConstantInt *AssumedUseGenericStateMachineC =
3994 ConstantInt::get(UseGenericStateMachineC->getIntegerType(), false);
3995 setUseGenericStateMachineOfKernelEnvironment(
3996 AssumedUseGenericStateMachineC);
3997 }
3998
3999 // Register virtual uses of functions we might need to preserve.
4000 auto RegisterVirtualUse = [&](RuntimeFunction RFKind,
4002 if (!OMPInfoCache.RFIs[RFKind].Declaration)
4003 return;
4004 A.registerVirtualUseCallback(*OMPInfoCache.RFIs[RFKind].Declaration, CB);
4005 };
4006
4007 // Add a dependence to ensure updates if the state changes.
4008 auto AddDependence = [](Attributor &A, const AAKernelInfo *KI,
4009 const AbstractAttribute *QueryingAA) {
4010 if (QueryingAA) {
4011 A.recordDependence(*KI, *QueryingAA, DepClassTy::OPTIONAL);
4012 }
4013 return true;
4014 };
4015
4016 Attributor::VirtualUseCallbackTy CustomStateMachineUseCB =
4017 [&](Attributor &A, const AbstractAttribute *QueryingAA) {
4018 // Whenever we create a custom state machine we will insert calls to
4019 // __kmpc_get_max_team_threads,
4020 // __kmpc_barrier_simple_generic,
4021 // __kmpc_kernel_parallel, and
4022 // __kmpc_kernel_end_parallel.
4023 // Not needed if we are on track for SPMDzation.
4024 if (SPMDCompatibilityTracker.isValidState())
4025 return AddDependence(A, this, QueryingAA);
4026 // Not needed if we can't rewrite due to an invalid state.
4027 if (!ReachedKnownParallelRegions.isValidState())
4028 return AddDependence(A, this, QueryingAA);
4029 return false;
4030 };
4031
4032 // Not needed if we are pre-runtime merge.
4033 if (!KernelInitCB->getCalledFunction()->isDeclaration()) {
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);
4042 }
4043
4044 // If we do not perform SPMDzation we do not need the virtual uses below.
4045 if (SPMDCompatibilityTracker.isAtFixpoint())
4046 return;
4047
4048 Attributor::VirtualUseCallbackTy HWThreadIdUseCB =
4049 [&](Attributor &A, const AbstractAttribute *QueryingAA) {
4050 // Whenever we perform SPMDzation we will insert
4051 // __kmpc_get_hardware_thread_id_in_block calls.
4052 if (!SPMDCompatibilityTracker.isValidState())
4053 return AddDependence(A, this, QueryingAA);
4054 return false;
4055 };
4056 RegisterVirtualUse(OMPRTL___kmpc_get_hardware_thread_id_in_block,
4057 HWThreadIdUseCB);
4058
4059 Attributor::VirtualUseCallbackTy SPMDBarrierUseCB =
4060 [&](Attributor &A, const AbstractAttribute *QueryingAA) {
4061 // Whenever we perform SPMDzation with guarding we will insert
4062 // __kmpc_simple_barrier_spmd calls. If SPMDzation failed, there is
4063 // nothing to guard, or there are no parallel regions, we don't need
4064 // the calls.
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);
4071 return false;
4072 };
4073 RegisterVirtualUse(OMPRTL___kmpc_barrier_simple_spmd, SPMDBarrierUseCB);
4074 }
4075
4076 /// Sanitize the string \p S such that it is a suitable global symbol name.
4077 static std::string sanitizeForGlobalName(std::string S) {
4078 std::replace_if(
4079 S.begin(), S.end(),
4080 [](const char C) {
4081 return !((C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z') ||
4082 (C >= '0' && C <= '9') || C == '_');
4083 },
4084 '.');
4085 return S;
4086 }
4087
4088 /// Modify the IR based on the KernelInfoState as the fixpoint iteration is
4089 /// finished now.
4090 ChangeStatus manifest(Attributor &A) override {
4091 // If we are not looking at a kernel with __kmpc_target_init and
4092 // __kmpc_target_deinit call we cannot actually manifest the information.
4093 if (!KernelInitCB || !KernelDeinitCB)
4094 return ChangeStatus::UNCHANGED;
4095
4096 ChangeStatus Changed = ChangeStatus::UNCHANGED;
4097
4098 bool HasBuiltStateMachine = true;
4099 if (!changeToSPMDMode(A, Changed)) {
4100 if (!KernelInitCB->getCalledFunction()->isDeclaration())
4101 HasBuiltStateMachine = buildCustomStateMachine(A, Changed);
4102 else
4103 HasBuiltStateMachine = false;
4104 }
4105
4106 // We need to reset KernelEnvC if specific rewriting is not done.
4107 ConstantStruct *ExistingKernelEnvC =
4109 ConstantInt *OldUseGenericStateMachineVal =
4110 KernelInfo::getUseGenericStateMachineFromKernelEnvironment(
4111 ExistingKernelEnvC);
4112 if (!HasBuiltStateMachine)
4113 setUseGenericStateMachineOfKernelEnvironment(
4114 OldUseGenericStateMachineVal);
4115
4116 // At last, update the KernelEnvc
4117 GlobalVariable *KernelEnvGV =
4119 if (KernelEnvGV->getInitializer() != KernelEnvC) {
4120 KernelEnvGV->setInitializer(KernelEnvC);
4121 Changed = ChangeStatus::CHANGED;
4122 }
4123
4124 return Changed;
4125 }
4126
4127 void insertInstructionGuardsHelper(Attributor &A) {
4128 auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
4129
4130 auto CreateGuardedRegion = [&](Instruction *RegionStartI,
4131 Instruction *RegionEndI) {
4132 LoopInfo *LI = nullptr;
4133 DominatorTree *DT = nullptr;
4134 MemorySSAUpdater *MSU = nullptr;
4135
4136 BasicBlock *ParentBB = RegionStartI->getParent();
4137 Function *Fn = ParentBB->getParent();
4138 Module &M = *Fn->getParent();
4139
4140 // Create all the blocks and logic.
4141 // ParentBB:
4142 // goto RegionCheckTidBB
4143 // RegionCheckTidBB:
4144 // Tid = __kmpc_hardware_thread_id()
4145 // if (Tid != 0)
4146 // goto RegionBarrierBB
4147 // RegionStartBB:
4148 // <execute instructions guarded>
4149 // goto RegionEndBB
4150 // RegionEndBB:
4151 // <store escaping values to shared mem>
4152 // goto RegionBarrierBB
4153 // RegionBarrierBB:
4154 // __kmpc_simple_barrier_spmd()
4155 // // second barrier is omitted if lacking escaping values.
4156 // <load escaping values from shared mem>
4157 // __kmpc_simple_barrier_spmd()
4158 // goto RegionExitBB
4159 // RegionExitBB:
4160 // <execute rest of instructions>
4161
4162 BasicBlock *RegionEndBB = SplitBlock(ParentBB, RegionEndI->getNextNode(),
4163 DT, LI, MSU, "region.guarded.end");
4164 BasicBlock *RegionBarrierBB =
4165 SplitBlock(RegionEndBB, &*RegionEndBB->getFirstInsertionPt(), DT, LI,
4166 MSU, "region.barrier");
4167 BasicBlock *RegionExitBB =
4168 SplitBlock(RegionBarrierBB, &*RegionBarrierBB->getFirstInsertionPt(),
4169 DT, LI, MSU, "region.exit");
4170 BasicBlock *RegionStartBB =
4171 SplitBlock(ParentBB, RegionStartI, DT, LI, MSU, "region.guarded");
4172
4173 assert(ParentBB->getUniqueSuccessor() == RegionStartBB &&
4174 "Expected a different CFG");
4175
4176 BasicBlock *RegionCheckTidBB = SplitBlock(
4177 ParentBB, ParentBB->getTerminator(), DT, LI, MSU, "region.check.tid");
4178
4179 // Register basic blocks with the Attributor.
4180 A.registerManifestAddedBasicBlock(*RegionEndBB);
4181 A.registerManifestAddedBasicBlock(*RegionBarrierBB);
4182 A.registerManifestAddedBasicBlock(*RegionExitBB);
4183 A.registerManifestAddedBasicBlock(*RegionStartBB);
4184 A.registerManifestAddedBasicBlock(*RegionCheckTidBB);
4185
4186 bool HasBroadcastValues = false;
4187 // Find escaping outputs from the guarded region to outside users and
4188 // broadcast their values to them.
4189 for (Instruction &I : *RegionStartBB) {
4190 SmallVector<Use *, 4> OutsideUses;
4191 for (Use &U : I.uses()) {
4192 Instruction &UsrI = *cast<Instruction>(U.getUser());
4193 if (UsrI.getParent() != RegionStartBB)
4194 OutsideUses.push_back(&U);
4195 }
4196
4197 if (OutsideUses.empty())
4198 continue;
4199
4200 HasBroadcastValues = true;
4201
4202 // Emit a global variable in shared memory to store the broadcasted
4203 // value.
4204 auto *SharedMem = new GlobalVariable(
4205 M, I.getType(), /* IsConstant */ false,
4207 sanitizeForGlobalName(
4208 (I.getName() + ".guarded.output.alloc").str()),
4210 static_cast<unsigned>(AddressSpace::Shared));
4211
4212 // Emit a store instruction to update the value.
4213 new StoreInst(&I, SharedMem,
4214 RegionEndBB->getTerminator()->getIterator());
4215
4216 LoadInst *LoadI = new LoadInst(
4217 I.getType(), SharedMem, I.getName() + ".guarded.output.load",
4218 RegionBarrierBB->getTerminator()->getIterator());
4219
4220 // Emit a load instruction and replace uses of the output value.
4221 for (Use *U : OutsideUses)
4222 A.changeUseAfterManifest(*U, *LoadI);
4223 }
4224
4225 auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
4226
4227 // Go to tid check BB in ParentBB.
4228 const DebugLoc DL = ParentBB->getTerminator()->getDebugLoc();
4229 ParentBB->getTerminator()->eraseFromParent();
4230 OpenMPIRBuilder::LocationDescription Loc(ParentBB->end(), DL);
4231 OMPInfoCache.OMPBuilder.updateToLocation(Loc);
4232 uint32_t SrcLocStrSize;
4233 auto *SrcLocStr =
4234 OMPInfoCache.OMPBuilder.getOrCreateSrcLocStr(Loc, SrcLocStrSize);
4235 Value *Ident =
4236 OMPInfoCache.OMPBuilder.getOrCreateIdent(SrcLocStr, SrcLocStrSize);
4237 UncondBrInst::Create(RegionCheckTidBB, ParentBB)->setDebugLoc(DL);
4238
4239 // Add check for Tid in RegionCheckTidBB
4240 RegionCheckTidBB->getTerminator()->eraseFromParent();
4241 OpenMPIRBuilder::LocationDescription LocRegionCheckTid(
4242 RegionCheckTidBB->end(), DL);
4243 OMPInfoCache.OMPBuilder.updateToLocation(LocRegionCheckTid);
4244 FunctionCallee HardwareTidFn =
4245 OMPInfoCache.OMPBuilder.getOrCreateRuntimeFunction(
4246 M, OMPRTL___kmpc_get_hardware_thread_id_in_block);
4247 CallInst *Tid =
4248 OMPInfoCache.OMPBuilder.Builder.CreateCall(HardwareTidFn, {});
4249 Tid->setDebugLoc(DL);
4250 OMPInfoCache.setCallingConvention(HardwareTidFn, Tid);
4251 Value *TidCheck = OMPInfoCache.OMPBuilder.Builder.CreateIsNull(Tid);
4252 OMPInfoCache.OMPBuilder.Builder
4253 .CreateCondBr(TidCheck, RegionStartBB, RegionBarrierBB)
4254 ->setDebugLoc(DL);
4255
4256 // First barrier for synchronization, ensures main thread has updated
4257 // values.
4258 FunctionCallee BarrierFn =
4259 OMPInfoCache.OMPBuilder.getOrCreateRuntimeFunction(
4260 M, OMPRTL___kmpc_barrier_simple_spmd);
4261 OMPInfoCache.OMPBuilder.updateToLocation(
4262 {RegionBarrierBB->getFirstInsertionPt(), DL});
4263 CallInst *Barrier =
4264 OMPInfoCache.OMPBuilder.Builder.CreateCall(BarrierFn, {Ident, Tid});
4265 OMPInfoCache.setCallingConvention(BarrierFn, Barrier);
4266
4267 // Second barrier ensures workers have read broadcast values.
4268 if (HasBroadcastValues) {
4269 CallInst *Barrier =
4270 CallInst::Create(BarrierFn, {Ident, Tid}, "",
4271 RegionBarrierBB->getTerminator()->getIterator());
4272 Barrier->setDebugLoc(DL);
4273 OMPInfoCache.setCallingConvention(BarrierFn, Barrier);
4274 }
4275 };
4276
4277 auto &AllocSharedRFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
4278 SmallPtrSet<BasicBlock *, 8> Visited;
4279 for (Instruction *GuardedI : SPMDCompatibilityTracker) {
4280 BasicBlock *BB = GuardedI->getParent();
4281 if (!Visited.insert(BB).second)
4282 continue;
4283
4285 Instruction *LastEffect = nullptr;
4286 BasicBlock::reverse_iterator IP = BB->rbegin(), IPEnd = BB->rend();
4287 while (++IP != IPEnd) {
4288 if (!IP->mayHaveSideEffects() && !IP->mayReadFromMemory())
4289 continue;
4290 Instruction *I = &*IP;
4291 if (OpenMPOpt::getCallIfRegularCall(*I, &AllocSharedRFI))
4292 continue;
4293 // Nothing tracked is sunk across a strict fence.
4294 if (isStrictFence(*I) || !I->user_empty() ||
4295 !SPMDCompatibilityTracker.contains(I)) {
4296 LastEffect = nullptr;
4297 continue;
4298 }
4299 if (LastEffect)
4300 Reorders.push_back({I, LastEffect});
4301 LastEffect = &*IP;
4302 }
4303 for (auto &Reorder : Reorders)
4304 Reorder.first->moveBefore(Reorder.second->getIterator());
4305 }
4306
4308
4309 for (Instruction *GuardedI : SPMDCompatibilityTracker) {
4310 BasicBlock *BB = GuardedI->getParent();
4311 auto *CalleeAA = A.lookupAAFor<AAKernelInfo>(
4312 IRPosition::function(*GuardedI->getFunction()), nullptr,
4313 DepClassTy::NONE);
4314 assert(CalleeAA != nullptr && "Expected Callee AAKernelInfo");
4315 auto &CalleeAAFunction = *cast<AAKernelInfoFunction>(CalleeAA);
4316 // Continue if instruction is already guarded.
4317 if (CalleeAAFunction.getGuardedInstructions().contains(GuardedI))
4318 continue;
4319
4320 Instruction *GuardedRegionStart = nullptr, *GuardedRegionEnd = nullptr;
4321 for (Instruction &I : *BB) {
4322 // A strict fence splits a guarded region so it stays outside it.
4323 if (isStrictFence(I)) {
4324 if (SPMDCompatibilityTracker.contains(&I))
4325 CalleeAAFunction.getGuardedInstructions().insert(&I);
4326 if (GuardedRegionStart) {
4327 GuardedRegions.push_back(
4328 std::make_pair(GuardedRegionStart, GuardedRegionEnd));
4329 GuardedRegionStart = nullptr;
4330 GuardedRegionEnd = nullptr;
4331 }
4332 continue;
4333 }
4334
4335 // If instruction I needs to be guarded update the guarded region
4336 // bounds.
4337 if (SPMDCompatibilityTracker.contains(&I)) {
4338 CalleeAAFunction.getGuardedInstructions().insert(&I);
4339 if (GuardedRegionStart)
4340 GuardedRegionEnd = &I;
4341 else
4342 GuardedRegionStart = GuardedRegionEnd = &I;
4343
4344 continue;
4345 }
4346
4347 // Instruction I does not need guarding, store
4348 // any region found and reset bounds.
4349 if (GuardedRegionStart) {
4350 GuardedRegions.push_back(
4351 std::make_pair(GuardedRegionStart, GuardedRegionEnd));
4352 GuardedRegionStart = nullptr;
4353 GuardedRegionEnd = nullptr;
4354 }
4355 }
4356 }
4357
4358 for (auto &GR : GuardedRegions)
4359 CreateGuardedRegion(GR.first, GR.second);
4360 }
4361
4362 void forceSingleThreadPerWorkgroupHelper(Attributor &A) {
4363 // Only allow 1 thread per workgroup to continue executing the user code.
4364 //
4365 // InitCB = __kmpc_target_init(...)
4366 // ThreadIdInBlock = __kmpc_get_hardware_thread_id_in_block();
4367 // if (ThreadIdInBlock != 0) return;
4368 // UserCode:
4369 // // user code
4370 //
4371 auto &Ctx = getAnchorValue().getContext();
4372 Function *Kernel = getAssociatedFunction();
4373 assert(Kernel && "Expected an associated function!");
4374
4375 // Create block for user code to branch to from initial block.
4376 BasicBlock *InitBB = KernelInitCB->getParent();
4377 BasicBlock *UserCodeBB = InitBB->splitBasicBlock(
4378 KernelInitCB->getNextNode(), "main.thread.user_code");
4379 BasicBlock *ReturnBB =
4380 BasicBlock::Create(Ctx, "exit.threads", Kernel, UserCodeBB);
4381
4382 // Register blocks with attributor:
4383 A.registerManifestAddedBasicBlock(*InitBB);
4384 A.registerManifestAddedBasicBlock(*UserCodeBB);
4385 A.registerManifestAddedBasicBlock(*ReturnBB);
4386
4387 // Debug location:
4388 const DebugLoc &DLoc = KernelInitCB->getDebugLoc();
4389 ReturnInst::Create(Ctx, ReturnBB)->setDebugLoc(DLoc);
4390 InitBB->getTerminator()->eraseFromParent();
4391
4392 // Prepare call to OMPRTL___kmpc_get_hardware_thread_id_in_block.
4393 Module &M = *Kernel->getParent();
4394 auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
4395 FunctionCallee ThreadIdInBlockFn =
4396 OMPInfoCache.OMPBuilder.getOrCreateRuntimeFunction(
4397 M, OMPRTL___kmpc_get_hardware_thread_id_in_block);
4398
4399 // Get thread ID in block.
4400 CallInst *ThreadIdInBlock =
4401 CallInst::Create(ThreadIdInBlockFn, "thread_id.in.block", InitBB);
4402 OMPInfoCache.setCallingConvention(ThreadIdInBlockFn, ThreadIdInBlock);
4403 ThreadIdInBlock->setDebugLoc(DLoc);
4404
4405 // Eliminate all threads in the block with ID not equal to 0:
4406 Instruction *IsMainThread =
4407 ICmpInst::Create(ICmpInst::ICmp, CmpInst::ICMP_NE, ThreadIdInBlock,
4408 ConstantInt::get(ThreadIdInBlock->getType(), 0),
4409 "thread.is_main", InitBB);
4410 IsMainThread->setDebugLoc(DLoc);
4411 CondBrInst::Create(IsMainThread, ReturnBB, UserCodeBB, InitBB);
4412 }
4413
4414 bool changeToSPMDMode(Attributor &A, ChangeStatus &Changed) {
4415 auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
4416
4417 if (!SPMDCompatibilityTracker.isAssumed()) {
4418 for (Instruction *NonCompatibleI : SPMDCompatibilityTracker) {
4419 if (!NonCompatibleI)
4420 continue;
4421
4422 // Skip diagnostics on calls to known OpenMP runtime functions for now.
4423 if (auto *CB = dyn_cast<CallBase>(NonCompatibleI))
4424 if (OMPInfoCache.RTLFunctions.contains(CB->getCalledFunction()))
4425 continue;
4426
4427 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
4428 ORA << "Value has potential side effects preventing SPMD-mode "
4429 "execution";
4430 if (isa<CallBase>(NonCompatibleI)) {
4431 ORA << ". Add `[[omp::assume(\"ompx_spmd_amenable\")]]` to "
4432 "the called function to override";
4433 }
4434 return ORA << ".";
4435 };
4436 A.emitRemark<OptimizationRemarkAnalysis>(NonCompatibleI, "OMP121",
4437 Remark);
4438
4439 LLVM_DEBUG(dbgs() << TAG << "SPMD-incompatible side-effect: "
4440 << *NonCompatibleI << "\n");
4441 }
4442
4443 return false;
4444 }
4445
4446 // Get the actual kernel, could be the caller of the anchor scope if we have
4447 // a debug wrapper.
4448 Function *Kernel = getAnchorScope();
4449 if (Kernel->hasLocalLinkage()) {
4450 assert(Kernel->hasOneUse() && "Unexpected use of debug kernel wrapper.");
4451 auto *CB = cast<CallBase>(Kernel->user_back());
4452 Kernel = CB->getCaller();
4453 }
4454 assert(omp::isOpenMPKernel(*Kernel) && "Expected kernel function!");
4455
4456 // Check if the kernel is already in SPMD mode, if so, return success.
4457 ConstantStruct *ExistingKernelEnvC =
4459 auto *ExecModeC =
4460 KernelInfo::getExecModeFromKernelEnvironment(ExistingKernelEnvC);
4461 const int8_t ExecModeVal = ExecModeC->getSExtValue();
4462 if (ExecModeVal != OMP_TGT_EXEC_MODE_GENERIC)
4463 return true;
4464
4465 // We will now unconditionally modify the IR, indicate a change.
4466 Changed = ChangeStatus::CHANGED;
4467
4468 // Do not use instruction guards when no parallel is present inside
4469 // the target region. Instead, only the main thread of each team executes
4470 // the user code, so there is no need to launch more threads.
4471 if (mayContainParallelRegion()) {
4472 insertInstructionGuardsHelper(A);
4473 } else {
4474 forceSingleThreadPerWorkgroupHelper(A);
4475 setMaxThreadsOfKernelEnvironment(
4476 ConstantInt::get(Type::getInt32Ty(Kernel->getContext()), 1));
4477 }
4478
4479 // Adjust the global exec mode flag that tells the runtime what mode this
4480 // kernel is executed in.
4481 assert(ExecModeVal == OMP_TGT_EXEC_MODE_GENERIC &&
4482 "Initially non-SPMD kernel has SPMD exec mode!");
4483 setExecModeOfKernelEnvironment(
4484 ConstantInt::get(ExecModeC->getIntegerType(),
4485 ExecModeVal | OMP_TGT_EXEC_MODE_GENERIC_SPMD));
4486
4487 ++NumOpenMPTargetRegionKernelsSPMD;
4488
4489 // Record that this kernel now runs SPMD so post-Attributor cleanup can drop
4490 // the now-dead parallel data-sharing wrapper without re-deriving the mode.
4491 OMPInfoCache.SPMDizedKernels.insert(Kernel);
4492
4493 auto Remark = [&](OptimizationRemark OR) {
4494 return OR << "Transformed generic-mode kernel to SPMD-mode.";
4495 };
4496 A.emitRemark<OptimizationRemark>(KernelInitCB, "OMP120", Remark);
4497 return true;
4498 };
4499
4500 bool buildCustomStateMachine(Attributor &A, ChangeStatus &Changed) {
4501 // If we have disabled state machine rewrites, don't make a custom one
4503 return false;
4504
4505 // Don't rewrite the state machine if we are not in a valid state.
4506 if (!ReachedKnownParallelRegions.isValidState())
4507 return false;
4508
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}))
4514 return false;
4515
4516 ConstantStruct *ExistingKernelEnvC =
4518
4519 // Check if the current configuration is non-SPMD and generic state machine.
4520 // If we already have SPMD mode or a custom state machine we do not need to
4521 // go any further. If it is anything but a constant something is weird and
4522 // we give up.
4523 ConstantInt *UseStateMachineC =
4524 KernelInfo::getUseGenericStateMachineFromKernelEnvironment(
4525 ExistingKernelEnvC);
4526 ConstantInt *ModeC =
4527 KernelInfo::getExecModeFromKernelEnvironment(ExistingKernelEnvC);
4528
4529 // If we are stuck with generic mode, try to create a custom device (=GPU)
4530 // state machine which is specialized for the parallel regions that are
4531 // reachable by the kernel.
4532 if (UseStateMachineC->isZero() ||
4534 return false;
4535
4536 Changed = ChangeStatus::CHANGED;
4537
4538 // If not SPMD mode, indicate we use a custom state machine now.
4539 setUseGenericStateMachineOfKernelEnvironment(
4540 ConstantInt::get(UseStateMachineC->getIntegerType(), false));
4541
4542 // If we don't actually need a state machine we are done here. This can
4543 // happen if there simply are no parallel regions. In the resulting kernel
4544 // all worker threads will simply exit right away, leaving the main thread
4545 // to do the work alone.
4546 if (!mayContainParallelRegion()) {
4547 ++NumOpenMPTargetRegionKernelsWithoutStateMachine;
4548
4549 auto Remark = [&](OptimizationRemark OR) {
4550 return OR << "Removing unused state machine from generic-mode kernel.";
4551 };
4552 A.emitRemark<OptimizationRemark>(KernelInitCB, "OMP130", Remark);
4553
4554 return true;
4555 }
4556
4557 // Keep track in the statistics of our new shiny custom state machine.
4558 if (ReachedUnknownParallelRegions.empty()) {
4559 ++NumOpenMPTargetRegionKernelsCustomStateMachineWithoutFallback;
4560
4561 auto Remark = [&](OptimizationRemark OR) {
4562 return OR << "Rewriting generic-mode kernel with a customized state "
4563 "machine.";
4564 };
4565 A.emitRemark<OptimizationRemark>(KernelInitCB, "OMP131", Remark);
4566 } else {
4567 ++NumOpenMPTargetRegionKernelsCustomStateMachineWithFallback;
4568
4569 auto Remark = [&](OptimizationRemarkAnalysis OR) {
4570 return OR << "Generic-mode kernel is executed with a customized state "
4571 "machine that requires a fallback.";
4572 };
4573 A.emitRemark<OptimizationRemarkAnalysis>(KernelInitCB, "OMP132", Remark);
4574
4575 // Tell the user why we ended up with a fallback.
4576 for (CallBase *UnknownParallelRegionCB : ReachedUnknownParallelRegions) {
4577 if (!UnknownParallelRegionCB)
4578 continue;
4579 auto Remark = [&](OptimizationRemarkAnalysis ORA) {
4580 return ORA << "Call may contain unknown parallel regions. Use "
4581 << "`[[omp::assume(\"omp_no_parallelism\")]]` to "
4582 "override.";
4583 };
4584 A.emitRemark<OptimizationRemarkAnalysis>(UnknownParallelRegionCB,
4585 "OMP133", Remark);
4586 }
4587 }
4588
4589 // Create all the blocks:
4590 //
4591 // InitCB = __kmpc_target_init(...)
4592 // MaxTeamThreads =
4593 // __kmpc_get_max_team_threads(/*IsSPMD=*/false);
4594 // IsWorkerCheckBB: bool IsWorker = InitCB != -1;
4595 // if (IsWorker) {
4596 // if (InitCB >= MaxTeamThreads) return;
4597 // SMBeginBB: __kmpc_barrier_simple_generic(...);
4598 // void *WorkFn;
4599 // bool Active = __kmpc_kernel_parallel(&WorkFn);
4600 // if (!WorkFn) return;
4601 // SMIsActiveCheckBB: if (Active) {
4602 // SMIfCascadeCurrentBB: if (WorkFn == <ParFn0>)
4603 // ParFn0(...);
4604 // SMIfCascadeCurrentBB: else if (WorkFn == <ParFn1>)
4605 // ParFn1(...);
4606 // ...
4607 // SMIfCascadeCurrentBB: else
4608 // ((WorkFnTy*)WorkFn)(...);
4609 // SMEndParallelBB: __kmpc_kernel_end_parallel(...);
4610 // }
4611 // SMDoneBB: __kmpc_barrier_simple_generic(...);
4612 // goto SMBeginBB;
4613 // }
4614 // UserCodeEntryBB: // user code
4615 // __kmpc_target_deinit(...)
4616 //
4617 auto &Ctx = getAnchorValue().getContext();
4618 Function *Kernel = getAssociatedFunction();
4619 assert(Kernel && "Expected an associated function!");
4620
4621 BasicBlock *InitBB = KernelInitCB->getParent();
4622 BasicBlock *UserCodeEntryBB = InitBB->splitBasicBlock(
4623 KernelInitCB->getNextNode(), "thread.user_code.check");
4624 BasicBlock *IsWorkerCheckBB =
4625 BasicBlock::Create(Ctx, "is_worker_check", Kernel, UserCodeEntryBB);
4626 BasicBlock *StateMachineBeginBB = BasicBlock::Create(
4627 Ctx, "worker_state_machine.begin", Kernel, UserCodeEntryBB);
4628 BasicBlock *StateMachineFinishedBB = BasicBlock::Create(
4629 Ctx, "worker_state_machine.finished", Kernel, UserCodeEntryBB);
4630 BasicBlock *StateMachineIsActiveCheckBB = BasicBlock::Create(
4631 Ctx, "worker_state_machine.is_active.check", Kernel, UserCodeEntryBB);
4632 BasicBlock *StateMachineIfCascadeCurrentBB =
4633 BasicBlock::Create(Ctx, "worker_state_machine.parallel_region.check",
4634 Kernel, UserCodeEntryBB);
4635 BasicBlock *StateMachineEndParallelBB =
4636 BasicBlock::Create(Ctx, "worker_state_machine.parallel_region.end",
4637 Kernel, UserCodeEntryBB);
4638 BasicBlock *StateMachineDoneBarrierBB = BasicBlock::Create(
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);
4649
4650 const DebugLoc &DLoc = KernelInitCB->getDebugLoc();
4651 ReturnInst::Create(Ctx, StateMachineFinishedBB)->setDebugLoc(DLoc);
4652 InitBB->getTerminator()->eraseFromParent();
4653
4654 Instruction *IsWorker =
4655 ICmpInst::Create(ICmpInst::ICmp, llvm::CmpInst::ICMP_NE, KernelInitCB,
4656 ConstantInt::getAllOnesValue(KernelInitCB->getType()),
4657 "thread.is_worker", InitBB);
4658 IsWorker->setDebugLoc(DLoc);
4659 CondBrInst::Create(IsWorker, IsWorkerCheckBB, UserCodeEntryBB, InitBB);
4660
4661 // How much of the block the main thread takes is the runtime's to know, so
4662 // ask it rather than subtracting a warp here. The mode is passed in because
4663 // this runs before the barrier that would make the shared one visible; it
4664 // is a constant, a custom state machine being built only for generic mode.
4665 Module &M = *Kernel->getParent();
4666 FunctionCallee MaxTeamThreadsFn =
4667 OMPInfoCache.OMPBuilder.getOrCreateRuntimeFunction(
4668 M, OMPRTL___kmpc_get_max_team_threads);
4669 Constant *IsSPMDArg = ConstantInt::get(OMPInfoCache.OMPBuilder.Int32, 0);
4670 CallInst *MaxTeamThreads = CallInst::Create(
4671 MaxTeamThreadsFn, {IsSPMDArg}, "max_team_threads", IsWorkerCheckBB);
4672 OMPInfoCache.setCallingConvention(MaxTeamThreadsFn, MaxTeamThreads);
4673 MaxTeamThreads->setDebugLoc(DLoc);
4674 Instruction *IsMainOrWorker = ICmpInst::Create(
4675 ICmpInst::ICmp, llvm::CmpInst::ICMP_SLT, KernelInitCB, MaxTeamThreads,
4676 "thread.is_main_or_worker", IsWorkerCheckBB);
4677 IsMainOrWorker->setDebugLoc(DLoc);
4678 CondBrInst::Create(IsMainOrWorker, StateMachineBeginBB,
4679 StateMachineFinishedBB, IsWorkerCheckBB);
4680
4681 // Create local storage for the work function pointer.
4682 const DataLayout &DL = M.getDataLayout();
4683 Type *VoidPtrTy = PointerType::getUnqual(Ctx);
4684 Instruction *WorkFnAI =
4685 new AllocaInst(VoidPtrTy, DL.getAllocaAddrSpace(), nullptr,
4686 "worker.work_fn.addr", Kernel->getEntryBlock().begin());
4687 WorkFnAI->setDebugLoc(DLoc);
4688
4689 OMPInfoCache.OMPBuilder.updateToLocation(
4690 OpenMPIRBuilder::LocationDescription(StateMachineBeginBB->end(), DLoc));
4691
4692 Value *Ident = KernelInfo::getIdentFromKernelEnvironment(KernelEnvC);
4693 Value *GTid = KernelInitCB;
4694
4695 FunctionCallee BarrierFn =
4696 OMPInfoCache.OMPBuilder.getOrCreateRuntimeFunction(
4697 M, OMPRTL___kmpc_barrier_simple_generic);
4698 CallInst *Barrier =
4699 CallInst::Create(BarrierFn, {Ident, GTid}, "", StateMachineBeginBB);
4700 OMPInfoCache.setCallingConvention(BarrierFn, Barrier);
4701 Barrier->setDebugLoc(DLoc);
4702
4703 if (WorkFnAI->getType()->getPointerAddressSpace() !=
4704 (unsigned int)AddressSpace::Generic) {
4705 WorkFnAI = new AddrSpaceCastInst(
4706 WorkFnAI, PointerType::get(Ctx, (unsigned int)AddressSpace::Generic),
4707 WorkFnAI->getName() + ".generic", StateMachineBeginBB);
4708 WorkFnAI->setDebugLoc(DLoc);
4709 }
4710
4711 FunctionCallee KernelParallelFn =
4712 OMPInfoCache.OMPBuilder.getOrCreateRuntimeFunction(
4713 M, OMPRTL___kmpc_kernel_parallel);
4714 CallInst *IsActiveWorker = CallInst::Create(
4715 KernelParallelFn, {WorkFnAI}, "worker.is_active", StateMachineBeginBB);
4716 OMPInfoCache.setCallingConvention(KernelParallelFn, IsActiveWorker);
4717 IsActiveWorker->setDebugLoc(DLoc);
4718 Instruction *WorkFn = new LoadInst(VoidPtrTy, WorkFnAI, "worker.work_fn",
4719 StateMachineBeginBB);
4720 WorkFn->setDebugLoc(DLoc);
4721
4722 FunctionType *ParallelRegionFnTy = FunctionType::get(
4723 Type::getVoidTy(Ctx), {Type::getInt16Ty(Ctx), Type::getInt32Ty(Ctx)},
4724 false);
4725
4726 Instruction *IsDone =
4727 ICmpInst::Create(ICmpInst::ICmp, llvm::CmpInst::ICMP_EQ, WorkFn,
4728 Constant::getNullValue(VoidPtrTy), "worker.is_done",
4729 StateMachineBeginBB);
4730 IsDone->setDebugLoc(DLoc);
4731 CondBrInst::Create(IsDone, StateMachineFinishedBB,
4732 StateMachineIsActiveCheckBB, StateMachineBeginBB)
4733 ->setDebugLoc(DLoc);
4734
4735 CondBrInst::Create(IsActiveWorker, StateMachineIfCascadeCurrentBB,
4736 StateMachineDoneBarrierBB, StateMachineIsActiveCheckBB)
4737 ->setDebugLoc(DLoc);
4738
4739 Value *ZeroArg =
4740 Constant::getNullValue(ParallelRegionFnTy->getParamType(0));
4741
4742 const unsigned int WrapperFunctionArgNo = 6;
4743
4744 // Now that we have most of the CFG skeleton it is time for the if-cascade
4745 // that checks the function pointer we got from the runtime against the
4746 // parallel regions we expect, if there are any.
4747 for (int I = 0, E = ReachedKnownParallelRegions.size(); I < E; ++I) {
4748 auto *CB = ReachedKnownParallelRegions[I];
4749 auto *ParallelRegion = dyn_cast<Function>(
4750 CB->getArgOperand(WrapperFunctionArgNo)->stripPointerCasts());
4751 BasicBlock *PRExecuteBB = BasicBlock::Create(
4752 Ctx, "worker_state_machine.parallel_region.execute", Kernel,
4753 StateMachineEndParallelBB);
4754 CallInst::Create(ParallelRegion, {ZeroArg, GTid}, "", PRExecuteBB)
4755 ->setDebugLoc(DLoc);
4756 UncondBrInst::Create(StateMachineEndParallelBB, PRExecuteBB)
4757 ->setDebugLoc(DLoc);
4758
4759 BasicBlock *PRNextBB =
4760 BasicBlock::Create(Ctx, "worker_state_machine.parallel_region.check",
4761 Kernel, StateMachineEndParallelBB);
4762 A.registerManifestAddedBasicBlock(*PRExecuteBB);
4763 A.registerManifestAddedBasicBlock(*PRNextBB);
4764
4765 // Check if we need to compare the pointer at all or if we can just
4766 // call the parallel region function.
4767 Value *IsPR;
4768 if (I + 1 < E || !ReachedUnknownParallelRegions.empty()) {
4769 Instruction *CmpI = ICmpInst::Create(
4770 ICmpInst::ICmp, llvm::CmpInst::ICMP_EQ, WorkFn, ParallelRegion,
4771 "worker.check_parallel_region", StateMachineIfCascadeCurrentBB);
4772 CmpI->setDebugLoc(DLoc);
4773 IsPR = CmpI;
4774 } else {
4775 IsPR = ConstantInt::getTrue(Ctx);
4776 }
4777
4778 CondBrInst::Create(IsPR, PRExecuteBB, PRNextBB,
4779 StateMachineIfCascadeCurrentBB)
4780 ->setDebugLoc(DLoc);
4781 StateMachineIfCascadeCurrentBB = PRNextBB;
4782 }
4783
4784 // At the end of the if-cascade we place the indirect function pointer call
4785 // in case we might need it, that is if there can be parallel regions we
4786 // have not handled in the if-cascade above.
4787 if (!ReachedUnknownParallelRegions.empty()) {
4788 StateMachineIfCascadeCurrentBB->setName(
4789 "worker_state_machine.parallel_region.fallback.execute");
4790 CallInst::Create(ParallelRegionFnTy, WorkFn, {ZeroArg, GTid}, "",
4791 StateMachineIfCascadeCurrentBB)
4792 ->setDebugLoc(DLoc);
4793 }
4794 UncondBrInst::Create(StateMachineEndParallelBB,
4795 StateMachineIfCascadeCurrentBB)
4796 ->setDebugLoc(DLoc);
4797
4798 FunctionCallee EndParallelFn =
4799 OMPInfoCache.OMPBuilder.getOrCreateRuntimeFunction(
4800 M, OMPRTL___kmpc_kernel_end_parallel);
4801 CallInst *EndParallel =
4802 CallInst::Create(EndParallelFn, {}, "", StateMachineEndParallelBB);
4803 OMPInfoCache.setCallingConvention(EndParallelFn, EndParallel);
4804 EndParallel->setDebugLoc(DLoc);
4805 UncondBrInst::Create(StateMachineDoneBarrierBB, StateMachineEndParallelBB)
4806 ->setDebugLoc(DLoc);
4807
4808 CallInst::Create(BarrierFn, {Ident, GTid}, "", StateMachineDoneBarrierBB)
4809 ->setDebugLoc(DLoc);
4810 UncondBrInst::Create(StateMachineBeginBB, StateMachineDoneBarrierBB)
4811 ->setDebugLoc(DLoc);
4812
4813 return true;
4814 }
4815
4816 /// Fixpoint iteration update function. Will be called every time a dependence
4817 /// changed its state (and in the beginning).
4818 ChangeStatus updateImpl(Attributor &A) override {
4819 KernelInfoState StateBefore = getState();
4820
4821 // When we leave this function this RAII will make sure the member
4822 // KernelEnvC is updated properly depending on the state. That member is
4823 // used for simplification of values and needs to be up to date at all
4824 // times.
4825 struct UpdateKernelEnvCRAII {
4826 AAKernelInfoFunction &AA;
4827
4828 UpdateKernelEnvCRAII(AAKernelInfoFunction &AA) : AA(AA) {}
4829
4830 ~UpdateKernelEnvCRAII() {
4831 if (!AA.KernelEnvC)
4832 return;
4833
4834 ConstantStruct *ExistingKernelEnvC =
4836
4837 if (!AA.isValidState()) {
4838 AA.KernelEnvC = ExistingKernelEnvC;
4839 return;
4840 }
4841
4842 if (!AA.ReachedKnownParallelRegions.isValidState())
4843 AA.setUseGenericStateMachineOfKernelEnvironment(
4844 KernelInfo::getUseGenericStateMachineFromKernelEnvironment(
4845 ExistingKernelEnvC));
4846
4847 if (!AA.SPMDCompatibilityTracker.isValidState())
4848 AA.setExecModeOfKernelEnvironment(
4849 KernelInfo::getExecModeFromKernelEnvironment(ExistingKernelEnvC));
4850
4851 ConstantInt *MayUseNestedParallelismC =
4852 KernelInfo::getMayUseNestedParallelismFromKernelEnvironment(
4853 AA.KernelEnvC);
4854 ConstantInt *NewMayUseNestedParallelismC = ConstantInt::get(
4855 MayUseNestedParallelismC->getIntegerType(), AA.NestedParallelism);
4856 AA.setMayUseNestedParallelismOfKernelEnvironment(
4857 NewMayUseNestedParallelismC);
4858 }
4859 } RAII(*this);
4860
4861 // Callback to check a read/write instruction.
4862 auto CheckRWInst = [&](Instruction &I) {
4863 // We handle calls later.
4864 if (isa<CallBase>(I))
4865 return true;
4866 // We only care about write effects.
4867 if (!I.mayWriteToMemory())
4868 return true;
4869 if (auto *SI = dyn_cast<StoreInst>(&I)) {
4870 const auto *UnderlyingObjsAA = A.getAAFor<AAUnderlyingObjects>(
4871 *this, IRPosition::value(*SI->getPointerOperand()),
4872 DepClassTy::OPTIONAL);
4873 auto *HS = A.getAAFor<AAHeapToStack>(
4874 *this, IRPosition::function(*I.getFunction()),
4875 DepClassTy::OPTIONAL);
4876 if (UnderlyingObjsAA &&
4877 UnderlyingObjsAA->forallUnderlyingObjects([&](Value &Obj) {
4878 if (AA::isAssumedThreadLocalObject(A, Obj, *this))
4879 return true;
4880 // Check for AAHeapToStack moved objects which must not be
4881 // guarded.
4882 auto *CB = dyn_cast<CallBase>(&Obj);
4883 return CB && HS && HS->isAssumedHeapToStack(*CB);
4884 }))
4885 return true;
4886 }
4887
4888 // Insert instruction that needs guarding.
4889 SPMDCompatibilityTracker.insert(&I);
4890 return true;
4891 };
4892
4893 bool UsedAssumedInformationInCheckRWInst = false;
4894 if (!SPMDCompatibilityTracker.isAtFixpoint())
4895 if (!A.checkForAllReadWriteInstructions(
4896 CheckRWInst, *this, UsedAssumedInformationInCheckRWInst))
4897 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
4898
4899 bool UsedAssumedInformationFromReachingKernels = false;
4900 if (!IsKernelEntry) {
4901 updateParallelLevels(A);
4902
4903 bool AllReachingKernelsKnown = true;
4904 updateReachingKernelEntries(A, AllReachingKernelsKnown);
4905 UsedAssumedInformationFromReachingKernels = !AllReachingKernelsKnown;
4906
4907 if (!SPMDCompatibilityTracker.empty()) {
4908 if (!ParallelLevels.isValidState())
4909 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
4910 else if (!ReachingKernelEntries.isValidState())
4911 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
4912 else {
4913 // Check if all reaching kernels agree on the mode as we can otherwise
4914 // not guard instructions. We might not be sure about the mode so we
4915 // we cannot fix the internal spmd-zation state either.
4916 int SPMD = 0, Generic = 0;
4917 for (auto *Kernel : ReachingKernelEntries) {
4918 auto *CBAA = A.getAAFor<AAKernelInfo>(
4919 *this, IRPosition::function(*Kernel), DepClassTy::OPTIONAL);
4920 if (CBAA && CBAA->SPMDCompatibilityTracker.isValidState() &&
4921 CBAA->SPMDCompatibilityTracker.isAssumed())
4922 ++SPMD;
4923 else
4924 ++Generic;
4925 if (!CBAA || !CBAA->SPMDCompatibilityTracker.isAtFixpoint())
4926 UsedAssumedInformationFromReachingKernels = true;
4927 }
4928 if (SPMD != 0 && Generic != 0)
4929 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
4930 }
4931 }
4932 }
4933
4934 // Callback to check a call instruction.
4935 bool AllParallelRegionStatesWereFixed = true;
4936 bool AllSPMDStatesWereFixed = true;
4937 auto CheckCallInst = [&](Instruction &I) {
4938 auto &CB = cast<CallBase>(I);
4939 // A runtime function that takes a callback runs the user's code inside
4940 // it, so whatever the callback reaches this kernel reaches too. Fold the
4941 // callback's state in; without this the call tells us nothing about the
4942 // parallel regions on the other side of it.
4943 if (Function *Callback = OMPInformationCache::getAnalyzableCallback(CB)) {
4944 LLVM_DEBUG(dbgs() << TAG << "folding in callback "
4945 << Callback->getName() << " of " << CB << "\n");
4946 if (auto *CallbackAA = A.getAAFor<AAKernelInfo>(
4947 *this, IRPosition::function(*Callback), DepClassTy::OPTIONAL)) {
4948 getState() ^= CallbackAA->getState();
4949 AllSPMDStatesWereFixed &=
4950 CallbackAA->SPMDCompatibilityTracker.isAtFixpoint();
4951 AllParallelRegionStatesWereFixed &=
4952 CallbackAA->ReachedKnownParallelRegions.isAtFixpoint();
4953 AllParallelRegionStatesWereFixed &=
4954 CallbackAA->ReachedUnknownParallelRegions.isAtFixpoint();
4955 }
4956 }
4957 auto *CBAA = A.getAAFor<AAKernelInfo>(
4958 *this, IRPosition::callsite_function(CB), DepClassTy::OPTIONAL);
4959 if (!CBAA)
4960 return false;
4961 getState() ^= CBAA->getState();
4962 AllSPMDStatesWereFixed &= CBAA->SPMDCompatibilityTracker.isAtFixpoint();
4963 AllParallelRegionStatesWereFixed &=
4964 CBAA->ReachedKnownParallelRegions.isAtFixpoint();
4965 AllParallelRegionStatesWereFixed &=
4966 CBAA->ReachedUnknownParallelRegions.isAtFixpoint();
4967 return true;
4968 };
4969
4970 bool UsedAssumedInformationInCheckCallInst = false;
4971 if (!A.checkForAllCallLikeInstructions(
4972 CheckCallInst, *this, UsedAssumedInformationInCheckCallInst)) {
4973 LLVM_DEBUG(dbgs() << TAG
4974 << "Failed to visit all call-like instructions!\n";);
4975 return indicatePessimisticFixpoint();
4976 }
4977
4978 // If we haven't used any assumed information for the reached parallel
4979 // region states we can fix it.
4980 if (!UsedAssumedInformationInCheckCallInst &&
4981 AllParallelRegionStatesWereFixed) {
4982 ReachedKnownParallelRegions.indicateOptimisticFixpoint();
4983 ReachedUnknownParallelRegions.indicateOptimisticFixpoint();
4984 }
4985
4986 // If we haven't used any assumed information for the SPMD state we can fix
4987 // it.
4988 if (!UsedAssumedInformationInCheckRWInst &&
4989 !UsedAssumedInformationInCheckCallInst &&
4990 !UsedAssumedInformationFromReachingKernels && AllSPMDStatesWereFixed)
4991 SPMDCompatibilityTracker.indicateOptimisticFixpoint();
4992
4993 return StateBefore == getState() ? ChangeStatus::UNCHANGED
4994 : ChangeStatus::CHANGED;
4995 }
4996
4997private:
4998 /// Update info regarding reaching kernels.
4999 void updateReachingKernelEntries(Attributor &A,
5000 bool &AllReachingKernelsKnown) {
5001 auto PredCallSite = [&](AbstractCallSite ACS) {
5002 Function *Caller = ACS.getInstruction()->getFunction();
5003
5004 assert(Caller && "Caller is nullptr");
5005
5006 auto *CAA = A.getOrCreateAAFor<AAKernelInfo>(
5007 IRPosition::function(*Caller), this, DepClassTy::REQUIRED);
5008 if (CAA && CAA->ReachingKernelEntries.isValidState()) {
5009 ReachingKernelEntries ^= CAA->ReachingKernelEntries;
5010 return true;
5011 }
5012
5013 // We lost track of the caller of the associated function, any kernel
5014 // could reach now.
5015 ReachingKernelEntries.indicatePessimisticFixpoint();
5016
5017 return true;
5018 };
5019
5020 if (!A.checkForAllCallSites(PredCallSite, *this,
5021 true /* RequireAllCallSites */,
5022 AllReachingKernelsKnown))
5023 ReachingKernelEntries.indicatePessimisticFixpoint();
5024 }
5025
5026 /// Update info regarding parallel levels.
5027 void updateParallelLevels(Attributor &A) {
5028 auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
5029 OMPInformationCache::RuntimeFunctionInfo &Parallel60RFI =
5030 OMPInfoCache.RFIs[OMPRTL___kmpc_parallel_60];
5031
5032 auto PredCallSite = [&](AbstractCallSite ACS) {
5033 Function *Caller = ACS.getInstruction()->getFunction();
5034
5035 assert(Caller && "Caller is nullptr");
5036
5037 auto *CAA =
5038 A.getOrCreateAAFor<AAKernelInfo>(IRPosition::function(*Caller));
5039 if (CAA && CAA->ParallelLevels.isValidState()) {
5040 // Any function that is called by `__kmpc_parallel_60` will not be
5041 // folded as the parallel level in the function is updated. In order to
5042 // get it right, all the analysis would depend on the implentation. That
5043 // said, if in the future any change to the implementation, the analysis
5044 // could be wrong. As a consequence, we are just conservative here.
5045 if (Caller == Parallel60RFI.Declaration) {
5046 ParallelLevels.indicatePessimisticFixpoint();
5047 return true;
5048 }
5049
5050 ParallelLevels ^= CAA->ParallelLevels;
5051
5052 return true;
5053 }
5054
5055 // We lost track of the caller of the associated function, any kernel
5056 // could reach now.
5057 ParallelLevels.indicatePessimisticFixpoint();
5058
5059 return true;
5060 };
5061
5062 bool AllCallSitesKnown = true;
5063 if (!A.checkForAllCallSites(PredCallSite, *this,
5064 true /* RequireAllCallSites */,
5065 AllCallSitesKnown))
5066 ParallelLevels.indicatePessimisticFixpoint();
5067 }
5068};
5069
5070/// The call site kernel info abstract attribute, basically, what can we say
5071/// about a call site with regards to the KernelInfoState. For now this simply
5072/// forwards the information from the callee.
5073struct AAKernelInfoCallSite : AAKernelInfo {
5074 AAKernelInfoCallSite(const IRPosition &IRP, Attributor &A)
5075 : AAKernelInfo(IRP, A) {}
5076
5077 void initialize(Attributor &A) override {
5078 AAKernelInfo::initialize(A);
5079
5080 CallBase &CB = cast<CallBase>(getAssociatedValue());
5081 auto *AssumptionAA = A.getAAFor<AAAssumptionInfo>(
5082 *this, IRPosition::callsite_function(CB), DepClassTy::OPTIONAL);
5083
5084 // Check for SPMD-mode assumptions.
5085 if (AssumptionAA && AssumptionAA->hasAssumption("ompx_spmd_amenable")) {
5086 indicateOptimisticFixpoint();
5087 return;
5088 }
5089
5090 // First weed out calls we do not care about, that is readonly/readnone
5091 // calls, intrinsics, and "no_openmp" calls. Neither of these can reach a
5092 // parallel region or anything else we are looking for.
5093 if (!CB.mayWriteToMemory() || isa<IntrinsicInst>(CB)) {
5094 indicateOptimisticFixpoint();
5095 return;
5096 }
5097
5098 // Next we check if we know the callee. If it is a known OpenMP function
5099 // we will handle them explicitly in the switch below. If it is not, we
5100 // will use an AAKernelInfo object on the callee to gather information and
5101 // merge that into the current state. The latter happens in the updateImpl.
5102 auto CheckCallee = [&](Function *Callee, unsigned NumCallees) {
5103 auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
5104 const auto &It = OMPInfoCache.RuntimeFunctionIDMap.find(Callee);
5105 if (It == OMPInfoCache.RuntimeFunctionIDMap.end()) {
5106 // Unknown caller or declarations are not analyzable, we give up.
5107 if (!Callee || !A.isFunctionIPOAmendable(*Callee)) {
5108
5109 // Unknown callees might contain parallel regions, except if they have
5110 // an appropriate assumption attached.
5111 if (!AssumptionAA ||
5112 !(AssumptionAA->hasAssumption("omp_no_openmp") ||
5113 AssumptionAA->hasAssumption("omp_no_parallelism")))
5114 ReachedUnknownParallelRegions.insert(&CB);
5115
5116 // If SPMDCompatibilityTracker is not fixed, we need to give up on the
5117 // idea we can run something unknown in SPMD-mode.
5118 if (!SPMDCompatibilityTracker.isAtFixpoint()) {
5119 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5120 SPMDCompatibilityTracker.insert(&CB);
5121 }
5122
5123 // We have updated the state for this unknown call properly, there
5124 // won't be any change so we indicate a fixpoint.
5125 indicateOptimisticFixpoint();
5126 }
5127 // If the callee is known and can be used in IPO, we will update the
5128 // state based on the callee state in updateImpl.
5129 return;
5130 }
5131 // More than one callee normally means an indirect call we cannot resolve.
5132 // A runtime function carrying !callback is the exception: the extra edge
5133 // is the callback, which we analyze rather than give up on.
5134 if (NumCallees > 1 && !Callee->hasMetadata(LLVMContext::MD_callback)) {
5135 indicatePessimisticFixpoint();
5136 return;
5137 }
5138
5139 RuntimeFunction RF = It->getSecond();
5140 switch (RF) {
5141 // All the functions we know are compatible with SPMD mode.
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:
5183 break;
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: {
5192 // Check the schedule and allow static schedule in SPMD mode.
5193 unsigned ScheduleArgOpNo = 2;
5194 auto *ScheduleTypeCI =
5195 dyn_cast<ConstantInt>(CB.getArgOperand(ScheduleArgOpNo));
5196 unsigned ScheduleTypeVal =
5197 ScheduleTypeCI ? ScheduleTypeCI->getZExtValue() : 0;
5198 switch (OMPScheduleType(ScheduleTypeVal)) {
5199 case OMPScheduleType::UnorderedStatic:
5200 case OMPScheduleType::UnorderedStaticChunked:
5201 case OMPScheduleType::OrderedDistribute:
5202 case OMPScheduleType::OrderedDistributeChunked:
5203 break;
5204 default:
5205 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5206 SPMDCompatibilityTracker.insert(&CB);
5207 break;
5208 };
5209 } break;
5210 case OMPRTL___kmpc_target_init:
5211 KernelInitCB = &CB;
5212 break;
5213 case OMPRTL___kmpc_target_deinit:
5214 KernelDeinitCB = &CB;
5215 break;
5216 case OMPRTL___kmpc_parallel_60:
5217 if (!handleParallel60(A, CB))
5218 indicatePessimisticFixpoint();
5219 return;
5220 case OMPRTL___kmpc_omp_task:
5221 // We do not look into tasks right now, just give up.
5222 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5223 SPMDCompatibilityTracker.insert(&CB);
5224 ReachedUnknownParallelRegions.insert(&CB);
5225 break;
5226 case OMPRTL___kmpc_alloc_shared:
5227 case OMPRTL___kmpc_free_shared:
5228 // Return without setting a fixpoint, to be resolved in updateImpl.
5229 return;
5230 // The twelve static-loop entry points split into the two groups below.
5231 // Both come out SPMD-incompatible, but for different reasons: the first
5232 // because the call is single-threaded by construction, the second only
5233 // because SPMD-ization cannot yet guard per iteration. They are kept
5234 // apart so the second can be relaxed on its own once it can.
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:
5239 // A plain `distribute` spreads its iterations over the teams, not over
5240 // the threads of a team: the runtime runs it with TId 0 and a team size
5241 // of one, and asserts the kernel is at parallel level 0. One thread per
5242 // block calls it, which is what generic mode gives it. In SPMD mode
5243 // every thread would call it, each running the whole of its block's
5244 // share of the loop body, so the kernel cannot be SPMD-ized however
5245 // analyzable the body is.
5246 if (!OMPInformationCache::getAnalyzableCallback(CB))
5247 ReachedUnknownParallelRegions.insert(&CB);
5248 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5249 SPMDCompatibilityTracker.insert(&CB);
5250 break;
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:
5259 // These index by the thread's own id, so unlike a plain distribute they
5260 // are meant to be called by every thread of the block, and a kernel
5261 // reaching one is not SPMD-incompatible for that reason alone. What
5262 // stops us is the transform rather than the analysis: SPMD-ization
5263 // guards whatever has to stay single-threaded with a block-wide
5264 // barrier, and a barrier placed inside a loop body only some threads
5265 // run is divergent. Until guarding can express "the thread that owns
5266 // this iteration", stay conservative here too.
5267 if (!OMPInformationCache::getAnalyzableCallback(CB))
5268 ReachedUnknownParallelRegions.insert(&CB);
5269 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5270 SPMDCompatibilityTracker.insert(&CB);
5271 break;
5272 default:
5273 // Unknown OpenMP runtime calls cannot be executed in SPMD-mode,
5274 // generally. However, they do not hide parallel regions.
5275 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5276 SPMDCompatibilityTracker.insert(&CB);
5277 break;
5278 }
5279 // All other OpenMP runtime calls will not reach parallel regions so they
5280 // can be safely ignored for now. Since it is a known OpenMP runtime call
5281 // we have now modeled all effects and there is no need for any update.
5282 indicateOptimisticFixpoint();
5283 };
5284
5285 const auto *AACE =
5286 A.getAAFor<AACallEdges>(*this, getIRPosition(), DepClassTy::OPTIONAL);
5287 if (!AACE || !AACE->getState().isValidState() || AACE->hasUnknownCallee()) {
5288 CheckCallee(getAssociatedFunction(), 1);
5289 return;
5290 }
5291 const auto &OptimisticEdges = AACE->getOptimisticEdges();
5292 for (auto *Callee : OptimisticEdges) {
5293 CheckCallee(Callee, OptimisticEdges.size());
5294 if (isAtFixpoint())
5295 break;
5296 }
5297 }
5298
5299 ChangeStatus updateImpl(Attributor &A) override {
5300 // TODO: Once we have call site specific value information we can provide
5301 // call site specific liveness information and then it makes
5302 // sense to specialize attributes for call sites arguments instead of
5303 // redirecting requests to the callee argument.
5304 auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
5305 KernelInfoState StateBefore = getState();
5306
5307 auto CheckCallee = [&](Function *F, int NumCallees) {
5308 const auto &It = OMPInfoCache.RuntimeFunctionIDMap.find(F);
5309
5310 // If F is not a runtime function, propagate the AAKernelInfo of the
5311 // callee.
5312 if (It == OMPInfoCache.RuntimeFunctionIDMap.end()) {
5313 const IRPosition &FnPos = IRPosition::function(*F);
5314 auto *FnAA =
5315 A.getAAFor<AAKernelInfo>(*this, FnPos, DepClassTy::REQUIRED);
5316 if (!FnAA)
5317 return indicatePessimisticFixpoint();
5318 if (getState() == FnAA->getState())
5319 return ChangeStatus::UNCHANGED;
5320 getState() = FnAA->getState();
5321 return ChangeStatus::CHANGED;
5322 }
5323 // See the matching check in initialize: a !callback runtime function has
5324 // a second call edge by construction, and it is one we can analyze.
5325 if (NumCallees > 1 && !F->hasMetadata(LLVMContext::MD_callback))
5326 return indicatePessimisticFixpoint();
5327
5328 CallBase &CB = cast<CallBase>(getAssociatedValue());
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;
5334 }
5335
5336 // F is a runtime function that allocates or frees memory, check
5337 // AAHeapToStack and AAHeapToShared.
5338 assert(
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");
5342
5343 auto *HeapToStackAA = A.getAAFor<AAHeapToStack>(
5344 *this, IRPosition::function(*CB.getCaller()), DepClassTy::OPTIONAL);
5345 auto *HeapToSharedAA = A.getAAFor<AAHeapToShared>(
5346 *this, IRPosition::function(*CB.getCaller()), DepClassTy::OPTIONAL);
5347
5348 RuntimeFunction RF = It->getSecond();
5349
5350 switch (RF) {
5351 // If neither HeapToStack nor HeapToShared assume the call is removed,
5352 // assume SPMD incompatibility.
5353 case OMPRTL___kmpc_alloc_shared:
5354 if ((!HeapToStackAA || !HeapToStackAA->isAssumedHeapToStack(CB)) &&
5355 (!HeapToSharedAA || !HeapToSharedAA->isAssumedHeapToShared(CB)))
5356 SPMDCompatibilityTracker.insert(&CB);
5357 break;
5358 case OMPRTL___kmpc_free_shared:
5359 if ((!HeapToStackAA ||
5360 !HeapToStackAA->isAssumedHeapToStackRemovedFree(CB)) &&
5361 (!HeapToSharedAA ||
5362 !HeapToSharedAA->isAssumedHeapToSharedRemovedFree(CB)))
5363 SPMDCompatibilityTracker.insert(&CB);
5364 break;
5365 default:
5366 SPMDCompatibilityTracker.indicatePessimisticFixpoint();
5367 SPMDCompatibilityTracker.insert(&CB);
5368 }
5369 return ChangeStatus::CHANGED;
5370 };
5371
5372 const auto *AACE =
5373 A.getAAFor<AACallEdges>(*this, getIRPosition(), DepClassTy::OPTIONAL);
5374 if (!AACE || !AACE->getState().isValidState() || AACE->hasUnknownCallee()) {
5375 if (Function *F = getAssociatedFunction())
5376 CheckCallee(F, /*NumCallees=*/1);
5377 } else {
5378 const auto &OptimisticEdges = AACE->getOptimisticEdges();
5379 for (auto *Callee : OptimisticEdges) {
5380 CheckCallee(Callee, OptimisticEdges.size());
5381 if (isAtFixpoint())
5382 break;
5383 }
5384 }
5385
5386 return StateBefore == getState() ? ChangeStatus::UNCHANGED
5387 : ChangeStatus::CHANGED;
5388 }
5389
5390 /// Deal with a __kmpc_parallel_60 call (\p CB). Returns true if the call was
5391 /// handled, if a problem occurred, false is returned.
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;
5398
5399 auto *ParallelRegion = dyn_cast<Function>(
5400 CB.getArgOperand(ParallelRegionOpArgNo)->stripPointerCasts());
5401 if (!ParallelRegion)
5402 return false;
5403
5404 ReachedKnownParallelRegions.insert(&CB);
5405 /// Check nested parallelism
5406 auto *FnAA = A.getAAFor<AAKernelInfo>(
5407 *this, IRPosition::function(*ParallelRegion), DepClassTy::OPTIONAL);
5408 NestedParallelism |= !FnAA || !FnAA->getState().isValidState() ||
5409 !FnAA->ReachedKnownParallelRegions.empty() ||
5410 !FnAA->ReachedKnownParallelRegions.isValidState() ||
5411 !FnAA->ReachedUnknownParallelRegions.isValidState() ||
5412 !FnAA->ReachedUnknownParallelRegions.empty();
5413 return true;
5414 }
5415};
5416
5417struct AAFoldRuntimeCall
5418 : public StateWrapper<BooleanState, AbstractAttribute> {
5419 using Base = StateWrapper<BooleanState, AbstractAttribute>;
5420
5421 AAFoldRuntimeCall(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
5422
5423 /// Statistics are tracked as part of manifest for now.
5424 void trackStatistics() const override {}
5425
5426 /// Create an abstract attribute biew for the position \p IRP.
5427 static AAFoldRuntimeCall &createForPosition(const IRPosition &IRP,
5428 Attributor &A);
5429
5430 StringRef getName() const override { return "AAFoldRuntimeCall"; }
5431
5432 const char *getIdAddr() const override { return &ID; }
5433
5434 /// This function should return true if the type of the \p AA is
5435 /// AAFoldRuntimeCall
5436 static bool classof(const AbstractAttribute *AA) {
5437 return (AA->getIdAddr() == &ID);
5438 }
5439
5440 static const char ID;
5441};
5442
5443struct AAFoldRuntimeCallCallSiteReturned : AAFoldRuntimeCall {
5444 AAFoldRuntimeCallCallSiteReturned(const IRPosition &IRP, Attributor &A)
5445 : AAFoldRuntimeCall(IRP, A) {}
5446
5447 const std::string getAsStr(Attributor *) const override {
5448 if (!isValidState())
5449 return "<invalid>";
5450
5451 std::string Str("simplified value: ");
5452
5453 if (!SimplifiedValue)
5454 return Str + std::string("none");
5455
5456 if (!*SimplifiedValue)
5457 return Str + std::string("nullptr");
5458
5459 if (ConstantInt *CI = dyn_cast<ConstantInt>(*SimplifiedValue))
5460 return Str + std::to_string(CI->getSExtValue());
5461
5462 return Str + std::string("unknown");
5463 }
5464
5465 void initialize(Attributor &A) override {
5467 indicatePessimisticFixpoint();
5468
5469 Function *Callee = getAssociatedFunction();
5470
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");
5475
5476 RFKind = It->getSecond();
5477
5478 CallBase &CB = cast<CallBase>(getAssociatedValue());
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!");
5485
5486 if (!isAtFixpoint()) {
5487 UsedAssumedInformation = true;
5488 if (AA)
5489 A.recordDependence(*this, *AA, DepClassTy::OPTIONAL);
5490 }
5491 return SimplifiedValue;
5492 });
5493 }
5494
5495 ChangeStatus updateImpl(Attributor &A) override {
5496 ChangeStatus Changed = ChangeStatus::UNCHANGED;
5497 switch (RFKind) {
5498 case OMPRTL___kmpc_is_spmd_exec_mode:
5499 Changed |= foldIsSPMDExecMode(A);
5500 break;
5501 case OMPRTL___kmpc_parallel_level:
5502 Changed |= foldParallelLevel(A);
5503 break;
5504 case OMPRTL___kmpc_get_hardware_num_threads_in_block:
5505 Changed = Changed | foldKernelFnAttribute(A, "omp_target_thread_limit");
5506 break;
5507 case OMPRTL___kmpc_get_hardware_num_blocks:
5508 Changed = Changed | foldKernelFnAttribute(A, "omp_target_num_teams");
5509 break;
5510 default:
5511 llvm_unreachable("Unhandled OpenMP runtime function!");
5512 }
5513
5514 return Changed;
5515 }
5516
5517 ChangeStatus manifest(Attributor &A) override {
5518 ChangeStatus Changed = ChangeStatus::UNCHANGED;
5519
5520 if (SimplifiedValue && *SimplifiedValue) {
5521 Instruction &I = *getCtxI();
5522 A.changeAfterManifest(IRPosition::inst(I), **SimplifiedValue);
5523 A.deleteAfterManifest(I);
5524
5525 CallBase *CB = dyn_cast<CallBase>(&I);
5526 auto Remark = [&](OptimizationRemark OR) {
5527 if (auto *C = dyn_cast<ConstantInt>(*SimplifiedValue))
5528 return OR << "Replacing OpenMP runtime call "
5529 << CB->getCalledFunction()->getName() << " with "
5530 << ore::NV("FoldedValue", C->getZExtValue()) << ".";
5531 return OR << "Replacing OpenMP runtime call "
5532 << CB->getCalledFunction()->getName() << ".";
5533 };
5534
5535 if (CB && EnableVerboseRemarks)
5536 A.emitRemark<OptimizationRemark>(CB, "OMP180", Remark);
5537
5538 LLVM_DEBUG(dbgs() << TAG << "Replacing runtime call: " << I << " with "
5539 << **SimplifiedValue << "\n");
5540
5541 Changed = ChangeStatus::CHANGED;
5542 }
5543
5544 return Changed;
5545 }
5546
5547 ChangeStatus indicatePessimisticFixpoint() override {
5548 SimplifiedValue = nullptr;
5549 return AAFoldRuntimeCall::indicatePessimisticFixpoint();
5550 }
5551
5552private:
5553 /// Fold __kmpc_is_spmd_exec_mode into a constant if possible.
5554 ChangeStatus foldIsSPMDExecMode(Attributor &A) {
5555 std::optional<Value *> SimplifiedValueBefore = SimplifiedValue;
5556
5557 unsigned AssumedSPMDCount = 0, KnownSPMDCount = 0;
5558 unsigned AssumedNonSPMDCount = 0, KnownNonSPMDCount = 0;
5559 auto *CallerKernelInfoAA = A.getAAFor<AAKernelInfo>(
5560 *this, IRPosition::function(*getAnchorScope()), DepClassTy::REQUIRED);
5561
5562 if (!CallerKernelInfoAA ||
5563 !CallerKernelInfoAA->ReachingKernelEntries.isValidState())
5564 return indicatePessimisticFixpoint();
5565
5566 for (Kernel K : CallerKernelInfoAA->ReachingKernelEntries) {
5567 auto *AA = A.getAAFor<AAKernelInfo>(*this, IRPosition::function(*K),
5568 DepClassTy::REQUIRED);
5569
5570 if (!AA || !AA->isValidState()) {
5571 SimplifiedValue = nullptr;
5572 return indicatePessimisticFixpoint();
5573 }
5574
5575 if (AA->SPMDCompatibilityTracker.isAssumed()) {
5576 if (AA->SPMDCompatibilityTracker.isAtFixpoint())
5577 ++KnownSPMDCount;
5578 else
5579 ++AssumedSPMDCount;
5580 } else {
5581 if (AA->SPMDCompatibilityTracker.isAtFixpoint())
5582 ++KnownNonSPMDCount;
5583 else
5584 ++AssumedNonSPMDCount;
5585 }
5586 }
5587
5588 if ((AssumedSPMDCount + KnownSPMDCount) &&
5589 (AssumedNonSPMDCount + KnownNonSPMDCount))
5590 return indicatePessimisticFixpoint();
5591
5592 auto &Ctx = getAnchorValue().getContext();
5593 if (KnownSPMDCount || AssumedSPMDCount) {
5594 assert(KnownNonSPMDCount == 0 && AssumedNonSPMDCount == 0 &&
5595 "Expected only SPMD kernels!");
5596 // All reaching kernels are in SPMD mode. Update all function calls to
5597 // __kmpc_is_spmd_exec_mode to 1.
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!");
5602 // All reaching kernels are in non-SPMD mode. Update all function
5603 // calls to __kmpc_is_spmd_exec_mode to 0.
5604 SimplifiedValue = ConstantInt::get(Type::getInt8Ty(Ctx), false);
5605 } else {
5606 // We have empty reaching kernels, therefore we cannot tell if the
5607 // associated call site can be folded. At this moment, SimplifiedValue
5608 // must be none.
5609 assert(!SimplifiedValue && "SimplifiedValue should be none");
5610 }
5611
5612 return SimplifiedValue == SimplifiedValueBefore ? ChangeStatus::UNCHANGED
5613 : ChangeStatus::CHANGED;
5614 }
5615
5616 /// Fold __kmpc_parallel_level into a constant if possible.
5617 ChangeStatus foldParallelLevel(Attributor &A) {
5618 std::optional<Value *> SimplifiedValueBefore = SimplifiedValue;
5619
5620 auto *CallerKernelInfoAA = A.getAAFor<AAKernelInfo>(
5621 *this, IRPosition::function(*getAnchorScope()), DepClassTy::REQUIRED);
5622
5623 if (!CallerKernelInfoAA ||
5624 !CallerKernelInfoAA->ParallelLevels.isValidState())
5625 return indicatePessimisticFixpoint();
5626
5627 if (!CallerKernelInfoAA->ReachingKernelEntries.isValidState())
5628 return indicatePessimisticFixpoint();
5629
5630 if (CallerKernelInfoAA->ReachingKernelEntries.empty()) {
5631 assert(!SimplifiedValue &&
5632 "SimplifiedValue should keep none at this point");
5633 return ChangeStatus::UNCHANGED;
5634 }
5635
5636 unsigned AssumedSPMDCount = 0, KnownSPMDCount = 0;
5637 unsigned AssumedNonSPMDCount = 0, KnownNonSPMDCount = 0;
5638 for (Kernel K : CallerKernelInfoAA->ReachingKernelEntries) {
5639 auto *AA = A.getAAFor<AAKernelInfo>(*this, IRPosition::function(*K),
5640 DepClassTy::REQUIRED);
5641 if (!AA || !AA->SPMDCompatibilityTracker.isValidState())
5642 return indicatePessimisticFixpoint();
5643
5644 if (AA->SPMDCompatibilityTracker.isAssumed()) {
5645 if (AA->SPMDCompatibilityTracker.isAtFixpoint())
5646 ++KnownSPMDCount;
5647 else
5648 ++AssumedSPMDCount;
5649 } else {
5650 if (AA->SPMDCompatibilityTracker.isAtFixpoint())
5651 ++KnownNonSPMDCount;
5652 else
5653 ++AssumedNonSPMDCount;
5654 }
5655 }
5656
5657 if ((AssumedSPMDCount + KnownSPMDCount) &&
5658 (AssumedNonSPMDCount + KnownNonSPMDCount))
5659 return indicatePessimisticFixpoint();
5660
5661 auto &Ctx = getAnchorValue().getContext();
5662 // If the caller can only be reached by SPMD kernel entries, the parallel
5663 // level is 1. Similarly, if the caller can only be reached by non-SPMD
5664 // kernel entries, it is 0.
5665 if (AssumedSPMDCount || KnownSPMDCount) {
5666 assert(KnownNonSPMDCount == 0 && AssumedNonSPMDCount == 0 &&
5667 "Expected only SPMD kernels!");
5668 SimplifiedValue = ConstantInt::get(Type::getInt8Ty(Ctx), 1);
5669 } else {
5670 assert(KnownSPMDCount == 0 && AssumedSPMDCount == 0 &&
5671 "Expected only non-SPMD kernels!");
5672 SimplifiedValue = ConstantInt::get(Type::getInt8Ty(Ctx), 0);
5673 }
5674 return SimplifiedValue == SimplifiedValueBefore ? ChangeStatus::UNCHANGED
5675 : ChangeStatus::CHANGED;
5676 }
5677
5678 ChangeStatus foldKernelFnAttribute(Attributor &A, llvm::StringRef Attr) {
5679 // Specialize only if all the calls agree with the attribute constant value
5680 int32_t CurrentAttrValue = -1;
5681 std::optional<Value *> SimplifiedValueBefore = SimplifiedValue;
5682
5683 auto *CallerKernelInfoAA = A.getAAFor<AAKernelInfo>(
5684 *this, IRPosition::function(*getAnchorScope()), DepClassTy::REQUIRED);
5685
5686 if (!CallerKernelInfoAA ||
5687 !CallerKernelInfoAA->ReachingKernelEntries.isValidState())
5688 return indicatePessimisticFixpoint();
5689
5690 // Iterate over the kernels that reach this function
5691 for (Kernel K : CallerKernelInfoAA->ReachingKernelEntries) {
5692 int32_t NextAttrVal = K->getFnAttributeAsParsedInteger(Attr, -1);
5693
5694 if (NextAttrVal == -1 ||
5695 (CurrentAttrValue != -1 && CurrentAttrValue != NextAttrVal))
5696 return indicatePessimisticFixpoint();
5697 CurrentAttrValue = NextAttrVal;
5698 }
5699
5700 if (CurrentAttrValue != -1) {
5701 auto &Ctx = getAnchorValue().getContext();
5702 SimplifiedValue =
5703 ConstantInt::get(Type::getInt32Ty(Ctx), CurrentAttrValue);
5704 }
5705 return SimplifiedValue == SimplifiedValueBefore ? ChangeStatus::UNCHANGED
5706 : ChangeStatus::CHANGED;
5707 }
5708
5709 /// An optional value the associated value is assumed to fold to. That is, we
5710 /// assume the associated value (which is a call) can be replaced by this
5711 /// simplified value.
5712 std::optional<Value *> SimplifiedValue;
5713
5714 /// The runtime function kind of the callee of the associated call site.
5715 RuntimeFunction RFKind;
5716};
5717
5718} // namespace
5719
5720/// Register folding callsite
5721void OpenMPOpt::registerFoldRuntimeCall(RuntimeFunction RF) {
5722 auto &RFI = OMPInfoCache.RFIs[RF];
5723 RFI.foreachUse(SCC, [&](Use &U, Function &F) {
5724 CallInst *CI = OpenMPOpt::getCallIfRegularCall(U, &RFI);
5725 if (!CI)
5726 return false;
5727 A.getOrCreateAAFor<AAFoldRuntimeCall>(
5728 IRPosition::callsite_returned(*CI), /* QueryingAA */ nullptr,
5729 DepClassTy::NONE, /* ForceUpdate */ false,
5730 /* UpdateAfterInit */ false);
5731 return false;
5732 });
5733}
5734
5735void OpenMPOpt::registerAAs(bool IsModulePass) {
5736 if (SCC.empty())
5737 return;
5738
5739 if (IsModulePass) {
5740 // Ensure we create the AAKernelInfo AAs first and without triggering an
5741 // update. This will make sure we register all value simplification
5742 // callbacks before any other AA has the chance to create an AAValueSimplify
5743 // or similar.
5744 auto CreateKernelInfoCB = [&](Use &, Function &Kernel) {
5745 A.getOrCreateAAFor<AAKernelInfo>(
5746 IRPosition::function(Kernel), /* QueryingAA */ nullptr,
5747 DepClassTy::NONE, /* ForceUpdate */ false,
5748 /* UpdateAfterInit */ false);
5749 return false;
5750 };
5751 OMPInformationCache::RuntimeFunctionInfo &InitRFI =
5752 OMPInfoCache.RFIs[OMPRTL___kmpc_target_init];
5753 InitRFI.foreachUse(SCC, CreateKernelInfoCB);
5754
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);
5759 }
5760
5761 // Create CallSite AA for all Getters.
5762 if (DeduceICVValues) {
5763 for (int Idx = 0; Idx < OMPInfoCache.ICVs.size() - 1; ++Idx) {
5764 auto ICVInfo = OMPInfoCache.ICVs[static_cast<InternalControlVar>(Idx)];
5765
5766 auto &GetterRFI = OMPInfoCache.RFIs[ICVInfo.Getter];
5767
5768 auto CreateAA = [&](Use &U, Function &Caller) {
5769 CallInst *CI = OpenMPOpt::getCallIfRegularCall(U, &GetterRFI);
5770 if (!CI)
5771 return false;
5772
5773 auto &CB = cast<CallBase>(*CI);
5774
5775 IRPosition CBPos = IRPosition::callsite_function(CB);
5776 A.getOrCreateAAFor<AAICVTracker>(CBPos);
5777 return false;
5778 };
5779
5780 GetterRFI.foreachUse(SCC, CreateAA);
5781 }
5782 }
5783
5784 // Create an ExecutionDomain AA for every function and a HeapToStack AA for
5785 // every function if there is a device kernel.
5786 if (!isOpenMPDevice(M))
5787 return;
5788
5789 for (auto *F : SCC) {
5790 if (F->isDeclaration())
5791 continue;
5792
5793 // We look at internal functions only on-demand but if any use is not a
5794 // direct call or outside the current set of analyzed functions, we have
5795 // to do it eagerly.
5796 if (F->hasLocalLinkage()) {
5797 if (llvm::all_of(F->uses(), [this](const Use &U) {
5798 const auto *CB = dyn_cast<CallBase>(U.getUser());
5799 return CB && CB->isCallee(&U) &&
5800 A.isRunOn(const_cast<Function *>(CB->getCaller()));
5801 }))
5802 continue;
5803 }
5804 registerAAsForFunction(A, *F);
5805 }
5806}
5807
5808void OpenMPOpt::registerAAsForFunction(Attributor &A, const Function &F) {
5809 auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
5810
5811 IRPosition FPos = IRPosition::function(F);
5812 A.getOrCreateAAFor<AAExecutionDomain>(FPos);
5813 if (F.hasFnAttribute(Attribute::Convergent))
5814 A.getOrCreateAAFor<AANonConvergent>(FPos);
5815
5816 bool FunctionUsesSharedAlloc = false;
5818 const OMPInformationCache::RuntimeFunctionInfo::UseVector *SharedAllocUses =
5819 OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared].getUseVector(
5820 const_cast<Function &>(F));
5821 FunctionUsesSharedAlloc = SharedAllocUses && !SharedAllocUses->empty();
5822 }
5823 bool HasHeapToStackCandidate = false;
5824 const TargetLibraryInfo *TLI = nullptr;
5825
5826 for (auto &I : instructions(F)) {
5827 if (auto *LI = dyn_cast<LoadInst>(&I)) {
5828 bool UsedAssumedInformation = false;
5829 A.getAssumedSimplified(IRPosition::value(*LI), /* AA */ nullptr,
5830 UsedAssumedInformation, AA::Interprocedural);
5831 A.getOrCreateAAFor<AAAddressSpace>(
5832 IRPosition::value(*LI->getPointerOperand()));
5833 continue;
5834 }
5835 if (auto *CI = dyn_cast<CallBase>(&I)) {
5836 if (!DisableOpenMPOptDeglobalization && !HasHeapToStackCandidate) {
5837 if (!TLI)
5838 TLI = A.getInfoCache().getTargetLibraryInfoForFunction(F);
5839 HasHeapToStackCandidate =
5840 isRemovableAlloc(CI, TLI) || getFreedOperand(CI, TLI);
5841 }
5842 if (CI->isIndirectCall())
5843 A.getOrCreateAAFor<AAIndirectCallInfo>(
5845 }
5846 if (auto *SI = dyn_cast<StoreInst>(&I)) {
5847 A.getOrCreateAAFor<AAIsDead>(IRPosition::value(*SI));
5848 A.getOrCreateAAFor<AAAddressSpace>(
5849 IRPosition::value(*SI->getPointerOperand()));
5850 continue;
5851 }
5852 if (auto *FI = dyn_cast<FenceInst>(&I)) {
5853 A.getOrCreateAAFor<AAIsDead>(IRPosition::value(*FI));
5854 continue;
5855 }
5856 if (auto *II = dyn_cast<IntrinsicInst>(&I)) {
5857 if (II->getIntrinsicID() == Intrinsic::assume) {
5858 A.getOrCreateAAFor<AAPotentialValues>(
5859 IRPosition::value(*II->getArgOperand(0)));
5860 continue;
5861 }
5862 }
5863 }
5864
5865 if (FunctionUsesSharedAlloc)
5866 A.getOrCreateAAFor<AAHeapToShared>(FPos);
5867 if (HasHeapToStackCandidate)
5868 A.getOrCreateAAFor<AAHeapToStack>(FPos);
5869}
5870
5871const char AAICVTracker::ID = 0;
5872const char AAKernelInfo::ID = 0;
5873const char AAExecutionDomain::ID = 0;
5874const char AAHeapToShared::ID = 0;
5875const char AAFoldRuntimeCall::ID = 0;
5876
5877AAICVTracker &AAICVTracker::createForPosition(const IRPosition &IRP,
5878 Attributor &A) {
5879 AAICVTracker *AA = nullptr;
5880 switch (IRP.getPositionKind()) {
5885 llvm_unreachable("ICVTracker can only be created for function position!");
5887 AA = new (A.Allocator) AAICVTrackerFunctionReturned(IRP, A);
5888 break;
5890 AA = new (A.Allocator) AAICVTrackerCallSiteReturned(IRP, A);
5891 break;
5893 AA = new (A.Allocator) AAICVTrackerCallSite(IRP, A);
5894 break;
5896 AA = new (A.Allocator) AAICVTrackerFunction(IRP, A);
5897 break;
5898 }
5899
5900 return *AA;
5901}
5902
5904 Attributor &A) {
5905 AAExecutionDomainFunction *AA = nullptr;
5906 switch (IRP.getPositionKind()) {
5915 "AAExecutionDomain can only be created for function position!");
5917 AA = new (A.Allocator) AAExecutionDomainFunction(IRP, A);
5918 break;
5919 }
5920
5921 return *AA;
5922}
5923
5924AAHeapToShared &AAHeapToShared::createForPosition(const IRPosition &IRP,
5925 Attributor &A) {
5926 AAHeapToSharedFunction *AA = nullptr;
5927 switch (IRP.getPositionKind()) {
5936 "AAHeapToShared can only be created for function position!");
5938 AA = new (A.Allocator) AAHeapToSharedFunction(IRP, A);
5939 break;
5940 }
5941
5942 return *AA;
5943}
5944
5945AAKernelInfo &AAKernelInfo::createForPosition(const IRPosition &IRP,
5946 Attributor &A) {
5947 AAKernelInfo *AA = nullptr;
5948 switch (IRP.getPositionKind()) {
5955 llvm_unreachable("KernelInfo can only be created for function position!");
5957 AA = new (A.Allocator) AAKernelInfoCallSite(IRP, A);
5958 break;
5960 AA = new (A.Allocator) AAKernelInfoFunction(IRP, A);
5961 break;
5962 }
5963
5964 return *AA;
5965}
5966
5967AAFoldRuntimeCall &AAFoldRuntimeCall::createForPosition(const IRPosition &IRP,
5968 Attributor &A) {
5969 AAFoldRuntimeCall *AA = nullptr;
5970 switch (IRP.getPositionKind()) {
5978 llvm_unreachable("KernelInfo can only be created for call site position!");
5980 AA = new (A.Allocator) AAFoldRuntimeCallCallSiteReturned(IRP, A);
5981 break;
5982 }
5983
5984 return *AA;
5985}
5986
5987/// Bound the if-cascade AAIndirectCallInfo builds for an indirect call. Device
5988/// code reaches its callees through function-pointer tables and virtual
5989/// dispatch, so a call site can see every address-taken candidate in the
5990/// module; specializing all of them costs more in code size and compile time
5991/// than the direct calls are worth.
5992///
5993/// This is a threshold on the call site rather than a limit on how many callees
5994/// get specialized: the Attributor asks about each callee with the same total,
5995/// so a site above the threshold keeps its indirect call instead of getting
5996/// this many direct ones plus a fallback.
5998 const AbstractAttribute &,
5999 CallBase &, Function &,
6000 unsigned NumAssumedCallees) {
6001 return NumAssumedCallees <= MaxCalleesForSpecialization;
6002}
6003
6005 if (!containsOpenMP(M))
6006 return PreservedAnalyses::all();
6008 return PreservedAnalyses::all();
6009
6012 KernelSet Kernels = getDeviceKernels(M);
6013
6015 LLVM_DEBUG(dbgs() << TAG << "Module before OpenMPOpt Module Pass:\n" << M);
6016
6017 auto IsCalled = [&](Function &F) {
6018 if (Kernels.contains(&F))
6019 return true;
6020 return !F.use_empty();
6021 };
6022
6023 auto EmitRemark = [&](Function &F) {
6024 auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);
6025 ORE.emit([&]() {
6026 OptimizationRemarkAnalysis ORA(DEBUG_TYPE, "OMP140", &F);
6027 return ORA << "Could not internalize function. "
6028 << "Some optimizations may not be possible. [OMP140]";
6029 });
6030 };
6031
6032 bool Changed = false;
6033
6034 // Create internal copies of each function if this is a kernel Module. This
6035 // allows iterprocedural passes to see every call edge.
6036 DenseMap<Function *, Function *> InternalizedMap;
6037 if (isOpenMPDevice(M)) {
6038 SmallPtrSet<Function *, 16> InternalizeFns;
6039 for (Function &F : M)
6040 if (!F.isDeclaration() && !Kernels.contains(&F) && IsCalled(F) &&
6043 InternalizeFns.insert(&F);
6044 } else if (!F.hasLocalLinkage() && !F.hasFnAttribute(Attribute::Cold)) {
6045 EmitRemark(F);
6046 }
6047 }
6048
6049 Changed |=
6050 Attributor::internalizeFunctions(InternalizeFns, InternalizedMap);
6051 }
6052
6053 // Look at every function in the Module unless it was internalized.
6054 SetVector<Function *> Functions;
6056 for (Function &F : M)
6057 if (!F.isDeclaration() && !InternalizedMap.lookup(&F)) {
6058 SCC.push_back(&F);
6059 Functions.insert(&F);
6060 }
6061
6062 if (SCC.empty())
6064
6065 AnalysisGetter AG(FAM);
6066
6067 auto OREGetter = [&FAM](Function *F) -> OptimizationRemarkEmitter & {
6068 return FAM.getResult<OptimizationRemarkEmitterAnalysis>(*F);
6069 };
6070
6071 BumpPtrAllocator Allocator;
6072 CallGraphUpdater CGUpdater;
6073
6074 bool PostLink = LTOPhase == ThinOrFullLTOPhase::FullLTOPostLink ||
6077 OMPInformationCache InfoCache(M, AG, Allocator, /*CGSCC*/ nullptr, PostLink);
6078
6079 unsigned MaxFixpointIterations =
6081
6082 AttributorConfig AC(CGUpdater);
6084 AC.IsModulePass = true;
6085 AC.RewriteSignatures = false;
6086 AC.MaxFixpointIterations = MaxFixpointIterations;
6087 AC.OREGetter = OREGetter;
6088 AC.PassName = DEBUG_TYPE;
6089 AC.InitializationCallback = OpenMPOpt::registerAAsForFunction;
6091 AC.IPOAmendableCB = [](const Function &F) {
6092 return F.hasFnAttribute("kernel");
6093 };
6094
6095 Attributor A(Functions, InfoCache, AC);
6096
6097 OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache, A);
6098 Changed |= OMPOpt.run(true);
6099
6100 // Optionally inline device functions for potentially better performance.
6102 for (Function &F : M)
6103 if (!F.isDeclaration() && !Kernels.contains(&F) &&
6104 !F.hasFnAttribute(Attribute::NoInline))
6105 F.addFnAttr(Attribute::AlwaysInline);
6106
6108 LLVM_DEBUG(dbgs() << TAG << "Module after OpenMPOpt Module Pass:\n" << M);
6109
6110 if (Changed)
6111 return PreservedAnalyses::none();
6112
6113 return PreservedAnalyses::all();
6114}
6115
6118 LazyCallGraph &CG,
6119 CGSCCUpdateResult &UR) {
6120 if (!containsOpenMP(*C.begin()->getFunction().getParent()))
6121 return PreservedAnalyses::all();
6123 return PreservedAnalyses::all();
6124
6126 // If there are kernels in the module, we have to run on all SCC's.
6127 for (LazyCallGraph::Node &N : C) {
6128 Function *Fn = &N.getFunction();
6129 SCC.push_back(Fn);
6130 }
6131
6132 if (SCC.empty())
6133 return PreservedAnalyses::all();
6134
6135 Module &M = *C.begin()->getFunction().getParent();
6136
6138 LLVM_DEBUG(dbgs() << TAG << "Module before OpenMPOpt CGSCC Pass:\n" << M);
6139
6141 AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
6142
6143 AnalysisGetter AG(FAM);
6144
6145 auto OREGetter = [&FAM](Function *F) -> OptimizationRemarkEmitter & {
6146 return FAM.getResult<OptimizationRemarkEmitterAnalysis>(*F);
6147 };
6148
6149 BumpPtrAllocator Allocator;
6150 CallGraphUpdater CGUpdater;
6151 CGUpdater.initialize(CG, C, AM, UR);
6152
6153 bool PostLink = LTOPhase == ThinOrFullLTOPhase::FullLTOPostLink ||
6157 OMPInformationCache InfoCache(*(Functions.back()->getParent()), AG, Allocator,
6158 /*CGSCC*/ &Functions, PostLink);
6159
6160 unsigned MaxFixpointIterations =
6162
6163 AttributorConfig AC(CGUpdater);
6165 AC.IsModulePass = false;
6166 AC.RewriteSignatures = false;
6167 AC.MaxFixpointIterations = MaxFixpointIterations;
6168 AC.OREGetter = OREGetter;
6169 AC.PassName = DEBUG_TYPE;
6170 AC.InitializationCallback = OpenMPOpt::registerAAsForFunction;
6172
6173 Attributor A(Functions, InfoCache, AC);
6174
6175 OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache, A);
6176 bool Changed = OMPOpt.run(false);
6177
6179 LLVM_DEBUG(dbgs() << TAG << "Module after OpenMPOpt CGSCC Pass:\n" << M);
6180
6181 if (Changed)
6182 return PreservedAnalyses::none();
6183
6184 return PreservedAnalyses::all();
6185}
6186
6188 return Fn.hasFnAttribute("kernel");
6189}
6190
6192 KernelSet Kernels;
6193
6194 for (Function &F : M)
6195 if (F.hasKernelCallingConv()) {
6196 // We are only interested in OpenMP target regions. Others, such as
6197 // kernels generated by CUDA but linked together, are not interesting to
6198 // this pass.
6199 if (isOpenMPKernel(F)) {
6200 ++NumOpenMPTargetRegionKernels;
6201 Kernels.insert(&F);
6202 } else
6203 ++NumNonOpenMPTargetRegionKernels;
6204 }
6205
6206 return Kernels;
6207}
6208
6210 Metadata *MD = M.getModuleFlag("openmp");
6211 if (!MD)
6212 return false;
6213
6214 return true;
6215}
6216
6218 Metadata *MD = M.getModuleFlag("openmp-device");
6219 if (!MD)
6220 return false;
6221
6222 return true;
6223}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
amdgpu aa AMDGPU Address space based Alias Analysis Wrapper
uint64_t uint64_t
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.
#define DEBUG_TYPE
static void emitRemark(const Function &F, OptimizationRemarkEmitter &ORE, bool Skip)
Loop::LoopBounds::Direction Direction
Definition LoopInfo.cpp:254
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Machine Check Debug Module
This file provides utility analysis objects describing memory locations.
#define T
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))
#define DEBUG_TYPE
Definition OpenMPOpt.cpp:74
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))
#define P(N)
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)
R600 Clause Merge
Basic Register Allocator
Remove Loads Into Fake Uses
std::pair< BasicBlock *, BasicBlock * > Edge
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
Definition Value.cpp:480
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)
Definition Statistic.h:171
This file contains some functions that are useful when dealing with strings.
#define LLVM_DEBUG(...)
Definition Debug.h:119
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.
Value * RHS
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),...
Definition ArrayRef.h:40
size_t size() const
Get the array size.
Definition ArrayRef.h:141
iterator end()
Definition BasicBlock.h:453
iterator begin()
Instruction iterator methods.
Definition BasicBlock.h:440
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.
Definition BasicBlock.h:213
reverse_iterator rbegin()
Definition BasicBlock.h:456
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition BasicBlock.h:206
LLVM_ABI const BasicBlock * getUniqueSuccessor() const
Return the successor of this block if it has a unique successor.
InstListType::reverse_iterator reverse_iterator
Definition BasicBlock.h:172
reverse_iterator rend()
Definition BasicBlock.h:458
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
Definition BasicBlock.h:237
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
void setCallingConv(CallingConv::ID CC)
bool arg_empty() const
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
Definition InstrTypes.h:769
@ ICMP_NE
not equal
Definition InstrTypes.h:762
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.
Definition Constants.h:87
IntegerType * getIntegerType() const
Variant of the getType() method to always return an IntegerType, which reduces the amount of casting ...
Definition Constants.h:198
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.
Definition Constants.h:219
int64_t getSExtValue() const
Return the constant as a 64-bit integer value after it has been sign extended as appropriate for the ...
Definition Constants.h:174
static LLVM_ABI ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
This is an important base class in LLVM.
Definition Constant.h:44
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.
Definition DenseMap.h:793
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition DenseMap.h:827
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.
Definition Error.h:336
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
Definition Function.h:794
const BasicBlock & front() const
Definition Function.h:845
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:352
void setEntryCount(uint64_t Count, const DenseSet< GlobalValue::GUID > *Imports=nullptr)
Set the entry count for this function.
Argument * getArg(unsigned i) const
Definition Function.h:871
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
Definition Function.cpp:731
LLVM_ABI bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
Definition Globals.cpp:408
bool hasLocalLinkage() const
Module * getParent()
Get the module that this global value is contained inside of...
@ PrivateLinkage
Like Internal, but omit from symbol table.
Definition GlobalValue.h:61
@ InternalLinkage
Rename collisions when linking (static functions).
Definition GlobalValue.h:60
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 ...
Definition Globals.cpp:613
CondBrInst * CreateCondBr(Value *Cond, BasicBlock *True, BasicBlock *False, MDNode *BranchWeights=nullptr, MDNode *Unpredictable=nullptr)
Create a conditional 'br Cond, TrueDest, FalseDest' instruction.
Definition IRBuilder.h:1212
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)
Definition IRBuilder.h:2561
Value * CreateIsNull(Value *Arg, const Twine &Name="")
Return a boolean value testing if Arg == 0.
Definition IRBuilder.h:2758
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
Definition Metadata.h:1437
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
Definition Metadata.h:1579
unsigned getNumOperands() const
Return number of MDNode operands.
Definition Metadata.h:1443
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.
Root of the metadata hierarchy.
Definition Metadata.h:64
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
const Triple & getTargetTriple() const
Get the target triple which is a string describing the target host.
Definition Module.h:328
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)
Diagnostic information for optimization analysis remarks.
The optimization diagnostic interface.
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.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
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.
Definition SetVector.h:57
size_type size() const
Determine the number of elements in the SetVector.
Definition SetVector.h:103
size_type count(const_arg_type key) const
Count the number of elements of a given key in the SetVector.
Definition SetVector.h:268
bool insert(const value_type &X)
Insert a new element into the SetVector.
Definition SetVector.h:157
size_type size() const
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.
iterator begin() const
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.
Definition StringRef.h:258
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:48
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
Definition Type.cpp:299
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.
Definition Use.h:35
LLVM_ABI bool replaceUsesOfWith(Value *From, Value *To)
Replace uses of one Value with another.
Definition User.cpp:25
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:257
LLVM_ABI void setName(const Twine &Name)
Change the name of the value.
Definition Value.cpp:390
bool hasOneUse() const
Return true if there is exactly one use of this value.
Definition Value.h:441
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:549
LLVMContext & getContext() const
All values hold a context through their type.
Definition Value.h:260
iterator_range< user_iterator > users()
Definition Value.h:428
User * user_back()
Definition Value.h:414
LLVM_ABI const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
Definition Value.cpp:708
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:315
const ParentTy * getParent() const
Definition ilist_node.h:34
self_iterator getIterator()
Definition ilist_node.h:123
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
Definition ilist_node.h:348
#define UINT64_MAX
Definition DataTypes.h:77
#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.
Definition Attributor.h:164
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.
@ Interprocedural
Definition Attributor.h:187
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)
@ Entry
Definition COFF.h:862
@ BasicBlock
Various leaf nodes.
Definition ISDOpcodes.h:83
@ SingleThread
Synchronized with respect to signal handlers executing in the same thread.
Definition LLVMContext.h:63
@ System
Synchronized with respect to all concurrently executing threads.
Definition LLVMContext.h:66
initializer< Ty > init(const Ty &Val)
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
Definition Transport.h:132
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
SetVector< Kernel > KernelSet
Set of kernels in the module.
Definition OpenMPOpt.h:24
Function * Kernel
Summary of a kernel (=entry point for target offloading).
Definition OpenMPOpt.h:21
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
Definition RDFGraph.h:385
bool empty() const
Definition BasicBlock.h:101
iterator end() const
Definition BasicBlock.h:89
friend class Instruction
Iterator for Instructions in a `BasicBlock.
Definition BasicBlock.h:73
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.
Definition STLExtras.h:316
@ Offset
Definition DWP.cpp:577
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1755
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.
Definition STLExtras.h:1685
bool succ_empty(const Instruction *I)
Definition CFG.h:141
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
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)
Definition APInt.h:2139
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
Definition InstrProf.h:143
AnalysisManager< LazyCallGraph::SCC, LazyCallGraph & > CGSCCAnalysisManager
The CGSCC analysis manager.
@ ThinLTOPostLink
ThinLTO postlink (backend compile) phase.
Definition Pass.h:81
@ FullLTOPostLink
Full LTO postlink (backend compile) phase.
Definition Pass.h:85
@ ThinLTOPreLink
ThinLTO prelink (summary) phase.
Definition Pass.h:79
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:753
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
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.
Definition AtomicScope.h:94
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...
Definition Casting.h:547
MutableArrayRef(T &OneElt) -> MutableArrayRef< T >
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
Definition Error.h:769
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...
Definition STLExtras.h:2028
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.
Definition Casting.h:559
auto predecessors(const MachineBasicBlock *BB)
ChangeStatus
{
Definition Attributor.h:476
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.
Definition Attributor.h:488
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
BumpPtrAllocatorImpl<> BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
Definition Allocator.h:391
@ End
Run the machine verifier once, at the end of the pipeline.
Definition CodeGen.h:320
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.
Definition MIRParser.h:39
#define N
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.
const char * PassName
}
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.
Definition Attributor.h:572
static const IRPosition callsite_returned(const CallBase &CB)
Create a position describing the returned value of CB.
Definition Attributor.h:640
static const IRPosition returned(const Function &F, const CallBaseContext *CBContext=nullptr)
Create a position describing the returned value of F.
Definition Attributor.h:622
static const IRPosition value(const Value &V, const CallBaseContext *CBContext=nullptr)
Create a position describing the value of V.
Definition Attributor.h:596
static const IRPosition inst(const Instruction &I, const CallBaseContext *CBContext=nullptr)
Create a position describing the instruction I.
Definition Attributor.h:608
@ IRP_ARGUMENT
An attribute for a function argument.
Definition Attributor.h:586
@ IRP_RETURNED
An attribute for the function return value.
Definition Attributor.h:582
@ IRP_CALL_SITE
An attribute for a call site (function scope).
Definition Attributor.h:585
@ IRP_CALL_SITE_RETURNED
An attribute for a call site return value.
Definition Attributor.h:583
@ IRP_FUNCTION
An attribute for a function (scope).
Definition Attributor.h:584
@ IRP_FLOAT
A position that is not associated with a spot suitable for attributes.
Definition Attributor.h:580
@ IRP_CALL_SITE_ARGUMENT
An attribute for a call site argument.
Definition Attributor.h:587
@ IRP_INVALID
An invalid position.
Definition Attributor.h:579
static const IRPosition function(const Function &F, const CallBaseContext *CBContext=nullptr)
Create a position describing the function scope of F.
Definition Attributor.h:615
Kind getPositionKind() const
Return the associated position kind.
Definition Attributor.h:846
static const IRPosition callsite_function(const CallBase &CB)
Create a position describing the function scope of CB.
Definition Attributor.h:635
Data structure to hold cached (LLVM-IR) information.
Defines various target-specific GPU grid values that must be consistent between host RTL (plugin),...