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