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