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