19548b74aSJohannes Doerfert //===-- IPO/OpenMPOpt.cpp - Collection of OpenMP specific optimizations ---===//
29548b74aSJohannes Doerfert //
39548b74aSJohannes Doerfert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
49548b74aSJohannes Doerfert // See https://llvm.org/LICENSE.txt for license information.
59548b74aSJohannes Doerfert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
69548b74aSJohannes Doerfert //
79548b74aSJohannes Doerfert //===----------------------------------------------------------------------===//
89548b74aSJohannes Doerfert //
99548b74aSJohannes Doerfert // OpenMP specific optimizations:
109548b74aSJohannes Doerfert //
119548b74aSJohannes Doerfert // - Deduplication of runtime calls, e.g., omp_get_thread_num.
12ca1560daSJoseph Huber // - Replacing globalized device memory with stack memory.
13ca1560daSJoseph Huber // - Replacing globalized device memory with shared memory.
14b910a109SJoseph Huber // - Parallel region merging.
15b910a109SJoseph Huber // - Transforming generic-mode device kernels to SPMD mode.
16b910a109SJoseph Huber // - Specializing the state machine for generic-mode device kernels.
179548b74aSJohannes Doerfert //
189548b74aSJohannes Doerfert //===----------------------------------------------------------------------===//
199548b74aSJohannes Doerfert 
209548b74aSJohannes Doerfert #include "llvm/Transforms/IPO/OpenMPOpt.h"
219548b74aSJohannes Doerfert 
229548b74aSJohannes Doerfert #include "llvm/ADT/EnumeratedArray.h"
2318283125SJoseph Huber #include "llvm/ADT/PostOrderIterator.h"
249548b74aSJohannes Doerfert #include "llvm/ADT/Statistic.h"
259548b74aSJohannes Doerfert #include "llvm/Analysis/CallGraph.h"
269548b74aSJohannes Doerfert #include "llvm/Analysis/CallGraphSCCPass.h"
274d4ea9acSHuber, Joseph #include "llvm/Analysis/OptimizationRemarkEmitter.h"
283a6bfcf2SGiorgis Georgakoudis #include "llvm/Analysis/ValueTracking.h"
299548b74aSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPConstants.h"
30e28936f6SJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
31d9659bf6SJohannes Doerfert #include "llvm/IR/Assumptions.h"
32d9659bf6SJohannes Doerfert #include "llvm/IR/DiagnosticInfo.h"
33514c033dSJohannes Doerfert #include "llvm/IR/GlobalValue.h"
34d9659bf6SJohannes Doerfert #include "llvm/IR/Instruction.h"
3568abc3d2SJoseph Huber #include "llvm/IR/IntrinsicInst.h"
369548b74aSJohannes Doerfert #include "llvm/InitializePasses.h"
379548b74aSJohannes Doerfert #include "llvm/Support/CommandLine.h"
389548b74aSJohannes Doerfert #include "llvm/Transforms/IPO.h"
397cfd267cSsstefan1 #include "llvm/Transforms/IPO/Attributor.h"
403a6bfcf2SGiorgis Georgakoudis #include "llvm/Transforms/Utils/BasicBlockUtils.h"
419548b74aSJohannes Doerfert #include "llvm/Transforms/Utils/CallGraphUpdater.h"
4297517055SGiorgis Georgakoudis #include "llvm/Transforms/Utils/CodeExtractor.h"
439548b74aSJohannes Doerfert 
449548b74aSJohannes Doerfert using namespace llvm;
459548b74aSJohannes Doerfert using namespace omp;
469548b74aSJohannes Doerfert 
479548b74aSJohannes Doerfert #define DEBUG_TYPE "openmp-opt"
489548b74aSJohannes Doerfert 
499548b74aSJohannes Doerfert static cl::opt<bool> DisableOpenMPOptimizations(
509548b74aSJohannes Doerfert     "openmp-opt-disable", cl::ZeroOrMore,
519548b74aSJohannes Doerfert     cl::desc("Disable OpenMP specific optimizations."), cl::Hidden,
529548b74aSJohannes Doerfert     cl::init(false));
539548b74aSJohannes Doerfert 
543a6bfcf2SGiorgis Georgakoudis static cl::opt<bool> EnableParallelRegionMerging(
553a6bfcf2SGiorgis Georgakoudis     "openmp-opt-enable-merging", cl::ZeroOrMore,
563a6bfcf2SGiorgis Georgakoudis     cl::desc("Enable the OpenMP region merging optimization."), cl::Hidden,
573a6bfcf2SGiorgis Georgakoudis     cl::init(false));
583a6bfcf2SGiorgis Georgakoudis 
590f426935Ssstefan1 static cl::opt<bool> PrintICVValues("openmp-print-icv-values", cl::init(false),
600f426935Ssstefan1                                     cl::Hidden);
61e8039ad4SJohannes Doerfert static cl::opt<bool> PrintOpenMPKernels("openmp-print-gpu-kernels",
62e8039ad4SJohannes Doerfert                                         cl::init(false), cl::Hidden);
630f426935Ssstefan1 
64496f8e5bSHamilton Tobon Mosquera static cl::opt<bool> HideMemoryTransferLatency(
65496f8e5bSHamilton Tobon Mosquera     "openmp-hide-memory-transfer-latency",
66496f8e5bSHamilton Tobon Mosquera     cl::desc("[WIP] Tries to hide the latency of host to device memory"
67496f8e5bSHamilton Tobon Mosquera              " transfers"),
68496f8e5bSHamilton Tobon Mosquera     cl::Hidden, cl::init(false));
69496f8e5bSHamilton Tobon Mosquera 
709548b74aSJohannes Doerfert STATISTIC(NumOpenMPRuntimeCallsDeduplicated,
719548b74aSJohannes Doerfert           "Number of OpenMP runtime calls deduplicated");
7255eb714aSRoman Lebedev STATISTIC(NumOpenMPParallelRegionsDeleted,
7355eb714aSRoman Lebedev           "Number of OpenMP parallel regions deleted");
749548b74aSJohannes Doerfert STATISTIC(NumOpenMPRuntimeFunctionsIdentified,
759548b74aSJohannes Doerfert           "Number of OpenMP runtime functions identified");
769548b74aSJohannes Doerfert STATISTIC(NumOpenMPRuntimeFunctionUsesIdentified,
779548b74aSJohannes Doerfert           "Number of OpenMP runtime function uses identified");
78e8039ad4SJohannes Doerfert STATISTIC(NumOpenMPTargetRegionKernels,
79e8039ad4SJohannes Doerfert           "Number of OpenMP target region entry points (=kernels) identified");
80514c033dSJohannes Doerfert STATISTIC(NumOpenMPTargetRegionKernelsSPMD,
81514c033dSJohannes Doerfert           "Number of OpenMP target region entry points (=kernels) executed in "
82514c033dSJohannes Doerfert           "SPMD-mode instead of generic-mode");
83d9659bf6SJohannes Doerfert STATISTIC(NumOpenMPTargetRegionKernelsWithoutStateMachine,
84d9659bf6SJohannes Doerfert           "Number of OpenMP target region entry points (=kernels) executed in "
85d9659bf6SJohannes Doerfert           "generic-mode without a state machines");
86d9659bf6SJohannes Doerfert STATISTIC(NumOpenMPTargetRegionKernelsCustomStateMachineWithFallback,
87d9659bf6SJohannes Doerfert           "Number of OpenMP target region entry points (=kernels) executed in "
88d9659bf6SJohannes Doerfert           "generic-mode with customized state machines with fallback");
89d9659bf6SJohannes Doerfert STATISTIC(NumOpenMPTargetRegionKernelsCustomStateMachineWithoutFallback,
90d9659bf6SJohannes Doerfert           "Number of OpenMP target region entry points (=kernels) executed in "
91d9659bf6SJohannes Doerfert           "generic-mode with customized state machines without fallback");
925b0581aeSJohannes Doerfert STATISTIC(
935b0581aeSJohannes Doerfert     NumOpenMPParallelRegionsReplacedInGPUStateMachine,
945b0581aeSJohannes Doerfert     "Number of OpenMP parallel regions replaced with ID in GPU state machines");
953a6bfcf2SGiorgis Georgakoudis STATISTIC(NumOpenMPParallelRegionsMerged,
963a6bfcf2SGiorgis Georgakoudis           "Number of OpenMP parallel regions merged");
976fc51c9fSJoseph Huber STATISTIC(NumBytesMovedToSharedMemory,
986fc51c9fSJoseph Huber           "Amount of memory pushed to shared memory");
999548b74aSJohannes Doerfert 
100263c4a3cSrathod-sahaab #if !defined(NDEBUG)
1019548b74aSJohannes Doerfert static constexpr auto TAG = "[" DEBUG_TYPE "]";
102a50c0b0dSMikael Holmen #endif
1039548b74aSJohannes Doerfert 
1049548b74aSJohannes Doerfert namespace {
1059548b74aSJohannes Doerfert 
1066fc51c9fSJoseph Huber enum class AddressSpace : unsigned {
1076fc51c9fSJoseph Huber   Generic = 0,
1086fc51c9fSJoseph Huber   Global = 1,
1096fc51c9fSJoseph Huber   Shared = 3,
1106fc51c9fSJoseph Huber   Constant = 4,
1116fc51c9fSJoseph Huber   Local = 5,
1126fc51c9fSJoseph Huber };
1136fc51c9fSJoseph Huber 
1146fc51c9fSJoseph Huber struct AAHeapToShared;
1156fc51c9fSJoseph Huber 
116b8235d2bSsstefan1 struct AAICVTracker;
117b8235d2bSsstefan1 
1187cfd267cSsstefan1 /// OpenMP specific information. For now, stores RFIs and ICVs also needed for
1197cfd267cSsstefan1 /// Attributor runs.
1207cfd267cSsstefan1 struct OMPInformationCache : public InformationCache {
1217cfd267cSsstefan1   OMPInformationCache(Module &M, AnalysisGetter &AG,
122624d34afSJohannes Doerfert                       BumpPtrAllocator &Allocator, SetVector<Function *> &CGSCC,
123e8039ad4SJohannes Doerfert                       SmallPtrSetImpl<Kernel> &Kernels)
124624d34afSJohannes Doerfert       : InformationCache(M, AG, Allocator, &CGSCC), OMPBuilder(M),
125624d34afSJohannes Doerfert         Kernels(Kernels) {
126624d34afSJohannes Doerfert 
12761238d26Ssstefan1     OMPBuilder.initialize();
1289548b74aSJohannes Doerfert     initializeRuntimeFunctions();
1290f426935Ssstefan1     initializeInternalControlVars();
1309548b74aSJohannes Doerfert   }
1319548b74aSJohannes Doerfert 
1320f426935Ssstefan1   /// Generic information that describes an internal control variable.
1330f426935Ssstefan1   struct InternalControlVarInfo {
1340f426935Ssstefan1     /// The kind, as described by InternalControlVar enum.
1350f426935Ssstefan1     InternalControlVar Kind;
1360f426935Ssstefan1 
1370f426935Ssstefan1     /// The name of the ICV.
1380f426935Ssstefan1     StringRef Name;
1390f426935Ssstefan1 
1400f426935Ssstefan1     /// Environment variable associated with this ICV.
1410f426935Ssstefan1     StringRef EnvVarName;
1420f426935Ssstefan1 
1430f426935Ssstefan1     /// Initial value kind.
1440f426935Ssstefan1     ICVInitValue InitKind;
1450f426935Ssstefan1 
1460f426935Ssstefan1     /// Initial value.
1470f426935Ssstefan1     ConstantInt *InitValue;
1480f426935Ssstefan1 
1490f426935Ssstefan1     /// Setter RTL function associated with this ICV.
1500f426935Ssstefan1     RuntimeFunction Setter;
1510f426935Ssstefan1 
1520f426935Ssstefan1     /// Getter RTL function associated with this ICV.
1530f426935Ssstefan1     RuntimeFunction Getter;
1540f426935Ssstefan1 
1550f426935Ssstefan1     /// RTL Function corresponding to the override clause of this ICV
1560f426935Ssstefan1     RuntimeFunction Clause;
1570f426935Ssstefan1   };
1580f426935Ssstefan1 
1599548b74aSJohannes Doerfert   /// Generic information that describes a runtime function
1609548b74aSJohannes Doerfert   struct RuntimeFunctionInfo {
1618855fec3SJohannes Doerfert 
1629548b74aSJohannes Doerfert     /// The kind, as described by the RuntimeFunction enum.
1639548b74aSJohannes Doerfert     RuntimeFunction Kind;
1649548b74aSJohannes Doerfert 
1659548b74aSJohannes Doerfert     /// The name of the function.
1669548b74aSJohannes Doerfert     StringRef Name;
1679548b74aSJohannes Doerfert 
1689548b74aSJohannes Doerfert     /// Flag to indicate a variadic function.
1699548b74aSJohannes Doerfert     bool IsVarArg;
1709548b74aSJohannes Doerfert 
1719548b74aSJohannes Doerfert     /// The return type of the function.
1729548b74aSJohannes Doerfert     Type *ReturnType;
1739548b74aSJohannes Doerfert 
1749548b74aSJohannes Doerfert     /// The argument types of the function.
1759548b74aSJohannes Doerfert     SmallVector<Type *, 8> ArgumentTypes;
1769548b74aSJohannes Doerfert 
1779548b74aSJohannes Doerfert     /// The declaration if available.
178f09f4b26SJohannes Doerfert     Function *Declaration = nullptr;
1799548b74aSJohannes Doerfert 
1809548b74aSJohannes Doerfert     /// Uses of this runtime function per function containing the use.
1818855fec3SJohannes Doerfert     using UseVector = SmallVector<Use *, 16>;
1828855fec3SJohannes Doerfert 
183b8235d2bSsstefan1     /// Clear UsesMap for runtime function.
184b8235d2bSsstefan1     void clearUsesMap() { UsesMap.clear(); }
185b8235d2bSsstefan1 
18654bd3751SJohannes Doerfert     /// Boolean conversion that is true if the runtime function was found.
18754bd3751SJohannes Doerfert     operator bool() const { return Declaration; }
18854bd3751SJohannes Doerfert 
1898855fec3SJohannes Doerfert     /// Return the vector of uses in function \p F.
1908855fec3SJohannes Doerfert     UseVector &getOrCreateUseVector(Function *F) {
191b8235d2bSsstefan1       std::shared_ptr<UseVector> &UV = UsesMap[F];
1928855fec3SJohannes Doerfert       if (!UV)
193b8235d2bSsstefan1         UV = std::make_shared<UseVector>();
1948855fec3SJohannes Doerfert       return *UV;
1958855fec3SJohannes Doerfert     }
1968855fec3SJohannes Doerfert 
1978855fec3SJohannes Doerfert     /// Return the vector of uses in function \p F or `nullptr` if there are
1988855fec3SJohannes Doerfert     /// none.
1998855fec3SJohannes Doerfert     const UseVector *getUseVector(Function &F) const {
20095e57072SDavid Blaikie       auto I = UsesMap.find(&F);
20195e57072SDavid Blaikie       if (I != UsesMap.end())
20295e57072SDavid Blaikie         return I->second.get();
20395e57072SDavid Blaikie       return nullptr;
2048855fec3SJohannes Doerfert     }
2058855fec3SJohannes Doerfert 
2068855fec3SJohannes Doerfert     /// Return how many functions contain uses of this runtime function.
2078855fec3SJohannes Doerfert     size_t getNumFunctionsWithUses() const { return UsesMap.size(); }
2089548b74aSJohannes Doerfert 
2099548b74aSJohannes Doerfert     /// Return the number of arguments (or the minimal number for variadic
2109548b74aSJohannes Doerfert     /// functions).
2119548b74aSJohannes Doerfert     size_t getNumArgs() const { return ArgumentTypes.size(); }
2129548b74aSJohannes Doerfert 
2139548b74aSJohannes Doerfert     /// Run the callback \p CB on each use and forget the use if the result is
2149548b74aSJohannes Doerfert     /// true. The callback will be fed the function in which the use was
2159548b74aSJohannes Doerfert     /// encountered as second argument.
216624d34afSJohannes Doerfert     void foreachUse(SmallVectorImpl<Function *> &SCC,
217624d34afSJohannes Doerfert                     function_ref<bool(Use &, Function &)> CB) {
218624d34afSJohannes Doerfert       for (Function *F : SCC)
219624d34afSJohannes Doerfert         foreachUse(CB, F);
220e099c7b6Ssstefan1     }
221e099c7b6Ssstefan1 
222e099c7b6Ssstefan1     /// Run the callback \p CB on each use within the function \p F and forget
223e099c7b6Ssstefan1     /// the use if the result is true.
224624d34afSJohannes Doerfert     void foreachUse(function_ref<bool(Use &, Function &)> CB, Function *F) {
2258855fec3SJohannes Doerfert       SmallVector<unsigned, 8> ToBeDeleted;
2269548b74aSJohannes Doerfert       ToBeDeleted.clear();
227e099c7b6Ssstefan1 
2288855fec3SJohannes Doerfert       unsigned Idx = 0;
229624d34afSJohannes Doerfert       UseVector &UV = getOrCreateUseVector(F);
230e099c7b6Ssstefan1 
2318855fec3SJohannes Doerfert       for (Use *U : UV) {
232e099c7b6Ssstefan1         if (CB(*U, *F))
2338855fec3SJohannes Doerfert           ToBeDeleted.push_back(Idx);
2348855fec3SJohannes Doerfert         ++Idx;
2358855fec3SJohannes Doerfert       }
2368855fec3SJohannes Doerfert 
2378855fec3SJohannes Doerfert       // Remove the to-be-deleted indices in reverse order as prior
238b726c557SJohannes Doerfert       // modifications will not modify the smaller indices.
2398855fec3SJohannes Doerfert       while (!ToBeDeleted.empty()) {
2408855fec3SJohannes Doerfert         unsigned Idx = ToBeDeleted.pop_back_val();
2418855fec3SJohannes Doerfert         UV[Idx] = UV.back();
2428855fec3SJohannes Doerfert         UV.pop_back();
2439548b74aSJohannes Doerfert       }
2449548b74aSJohannes Doerfert     }
2458855fec3SJohannes Doerfert 
2468855fec3SJohannes Doerfert   private:
2478855fec3SJohannes Doerfert     /// Map from functions to all uses of this runtime function contained in
2488855fec3SJohannes Doerfert     /// them.
249b8235d2bSsstefan1     DenseMap<Function *, std::shared_ptr<UseVector>> UsesMap;
250d9659bf6SJohannes Doerfert 
251d9659bf6SJohannes Doerfert   public:
252d9659bf6SJohannes Doerfert     /// Iterators for the uses of this runtime function.
253d9659bf6SJohannes Doerfert     decltype(UsesMap)::iterator begin() { return UsesMap.begin(); }
254d9659bf6SJohannes Doerfert     decltype(UsesMap)::iterator end() { return UsesMap.end(); }
2559548b74aSJohannes Doerfert   };
2569548b74aSJohannes Doerfert 
2577cfd267cSsstefan1   /// An OpenMP-IR-Builder instance
2587cfd267cSsstefan1   OpenMPIRBuilder OMPBuilder;
2597cfd267cSsstefan1 
2607cfd267cSsstefan1   /// Map from runtime function kind to the runtime function description.
2617cfd267cSsstefan1   EnumeratedArray<RuntimeFunctionInfo, RuntimeFunction,
2627cfd267cSsstefan1                   RuntimeFunction::OMPRTL___last>
2637cfd267cSsstefan1       RFIs;
2647cfd267cSsstefan1 
265d9659bf6SJohannes Doerfert   /// Map from function declarations/definitions to their runtime enum type.
266d9659bf6SJohannes Doerfert   DenseMap<Function *, RuntimeFunction> RuntimeFunctionIDMap;
267d9659bf6SJohannes Doerfert 
2680f426935Ssstefan1   /// Map from ICV kind to the ICV description.
2690f426935Ssstefan1   EnumeratedArray<InternalControlVarInfo, InternalControlVar,
2700f426935Ssstefan1                   InternalControlVar::ICV___last>
2710f426935Ssstefan1       ICVs;
2720f426935Ssstefan1 
2730f426935Ssstefan1   /// Helper to initialize all internal control variable information for those
2740f426935Ssstefan1   /// defined in OMPKinds.def.
2750f426935Ssstefan1   void initializeInternalControlVars() {
2760f426935Ssstefan1 #define ICV_RT_SET(_Name, RTL)                                                 \
2770f426935Ssstefan1   {                                                                            \
2780f426935Ssstefan1     auto &ICV = ICVs[_Name];                                                   \
2790f426935Ssstefan1     ICV.Setter = RTL;                                                          \
2800f426935Ssstefan1   }
2810f426935Ssstefan1 #define ICV_RT_GET(Name, RTL)                                                  \
2820f426935Ssstefan1   {                                                                            \
2830f426935Ssstefan1     auto &ICV = ICVs[Name];                                                    \
2840f426935Ssstefan1     ICV.Getter = RTL;                                                          \
2850f426935Ssstefan1   }
2860f426935Ssstefan1 #define ICV_DATA_ENV(Enum, _Name, _EnvVarName, Init)                           \
2870f426935Ssstefan1   {                                                                            \
2880f426935Ssstefan1     auto &ICV = ICVs[Enum];                                                    \
2890f426935Ssstefan1     ICV.Name = _Name;                                                          \
2900f426935Ssstefan1     ICV.Kind = Enum;                                                           \
2910f426935Ssstefan1     ICV.InitKind = Init;                                                       \
2920f426935Ssstefan1     ICV.EnvVarName = _EnvVarName;                                              \
2930f426935Ssstefan1     switch (ICV.InitKind) {                                                    \
294951e43f3Ssstefan1     case ICV_IMPLEMENTATION_DEFINED:                                           \
2950f426935Ssstefan1       ICV.InitValue = nullptr;                                                 \
2960f426935Ssstefan1       break;                                                                   \
297951e43f3Ssstefan1     case ICV_ZERO:                                                             \
2986aab27baSsstefan1       ICV.InitValue = ConstantInt::get(                                        \
2996aab27baSsstefan1           Type::getInt32Ty(OMPBuilder.Int32->getContext()), 0);                \
3000f426935Ssstefan1       break;                                                                   \
301951e43f3Ssstefan1     case ICV_FALSE:                                                            \
3026aab27baSsstefan1       ICV.InitValue = ConstantInt::getFalse(OMPBuilder.Int1->getContext());    \
3030f426935Ssstefan1       break;                                                                   \
304951e43f3Ssstefan1     case ICV_LAST:                                                             \
3050f426935Ssstefan1       break;                                                                   \
3060f426935Ssstefan1     }                                                                          \
3070f426935Ssstefan1   }
3080f426935Ssstefan1 #include "llvm/Frontend/OpenMP/OMPKinds.def"
3090f426935Ssstefan1   }
3100f426935Ssstefan1 
3117cfd267cSsstefan1   /// Returns true if the function declaration \p F matches the runtime
3127cfd267cSsstefan1   /// function types, that is, return type \p RTFRetType, and argument types
3137cfd267cSsstefan1   /// \p RTFArgTypes.
3147cfd267cSsstefan1   static bool declMatchesRTFTypes(Function *F, Type *RTFRetType,
3157cfd267cSsstefan1                                   SmallVector<Type *, 8> &RTFArgTypes) {
3167cfd267cSsstefan1     // TODO: We should output information to the user (under debug output
3177cfd267cSsstefan1     //       and via remarks).
3187cfd267cSsstefan1 
3197cfd267cSsstefan1     if (!F)
3207cfd267cSsstefan1       return false;
3217cfd267cSsstefan1     if (F->getReturnType() != RTFRetType)
3227cfd267cSsstefan1       return false;
3237cfd267cSsstefan1     if (F->arg_size() != RTFArgTypes.size())
3247cfd267cSsstefan1       return false;
3257cfd267cSsstefan1 
3267cfd267cSsstefan1     auto RTFTyIt = RTFArgTypes.begin();
3277cfd267cSsstefan1     for (Argument &Arg : F->args()) {
3287cfd267cSsstefan1       if (Arg.getType() != *RTFTyIt)
3297cfd267cSsstefan1         return false;
3307cfd267cSsstefan1 
3317cfd267cSsstefan1       ++RTFTyIt;
3327cfd267cSsstefan1     }
3337cfd267cSsstefan1 
3347cfd267cSsstefan1     return true;
3357cfd267cSsstefan1   }
3367cfd267cSsstefan1 
337b726c557SJohannes Doerfert   // Helper to collect all uses of the declaration in the UsesMap.
338b8235d2bSsstefan1   unsigned collectUses(RuntimeFunctionInfo &RFI, bool CollectStats = true) {
3397cfd267cSsstefan1     unsigned NumUses = 0;
3407cfd267cSsstefan1     if (!RFI.Declaration)
3417cfd267cSsstefan1       return NumUses;
3427cfd267cSsstefan1     OMPBuilder.addAttributes(RFI.Kind, *RFI.Declaration);
3437cfd267cSsstefan1 
344b8235d2bSsstefan1     if (CollectStats) {
3457cfd267cSsstefan1       NumOpenMPRuntimeFunctionsIdentified += 1;
3467cfd267cSsstefan1       NumOpenMPRuntimeFunctionUsesIdentified += RFI.Declaration->getNumUses();
347b8235d2bSsstefan1     }
3487cfd267cSsstefan1 
3497cfd267cSsstefan1     // TODO: We directly convert uses into proper calls and unknown uses.
3507cfd267cSsstefan1     for (Use &U : RFI.Declaration->uses()) {
3517cfd267cSsstefan1       if (Instruction *UserI = dyn_cast<Instruction>(U.getUser())) {
3527cfd267cSsstefan1         if (ModuleSlice.count(UserI->getFunction())) {
3537cfd267cSsstefan1           RFI.getOrCreateUseVector(UserI->getFunction()).push_back(&U);
3547cfd267cSsstefan1           ++NumUses;
3557cfd267cSsstefan1         }
3567cfd267cSsstefan1       } else {
3577cfd267cSsstefan1         RFI.getOrCreateUseVector(nullptr).push_back(&U);
3587cfd267cSsstefan1         ++NumUses;
3597cfd267cSsstefan1       }
3607cfd267cSsstefan1     }
3617cfd267cSsstefan1     return NumUses;
362b8235d2bSsstefan1   }
3637cfd267cSsstefan1 
36497517055SGiorgis Georgakoudis   // Helper function to recollect uses of a runtime function.
36597517055SGiorgis Georgakoudis   void recollectUsesForFunction(RuntimeFunction RTF) {
36697517055SGiorgis Georgakoudis     auto &RFI = RFIs[RTF];
367b8235d2bSsstefan1     RFI.clearUsesMap();
368b8235d2bSsstefan1     collectUses(RFI, /*CollectStats*/ false);
369b8235d2bSsstefan1   }
37097517055SGiorgis Georgakoudis 
37197517055SGiorgis Georgakoudis   // Helper function to recollect uses of all runtime functions.
37297517055SGiorgis Georgakoudis   void recollectUses() {
37397517055SGiorgis Georgakoudis     for (int Idx = 0; Idx < RFIs.size(); ++Idx)
37497517055SGiorgis Georgakoudis       recollectUsesForFunction(static_cast<RuntimeFunction>(Idx));
375b8235d2bSsstefan1   }
376b8235d2bSsstefan1 
377b8235d2bSsstefan1   /// Helper to initialize all runtime function information for those defined
378b8235d2bSsstefan1   /// in OpenMPKinds.def.
379b8235d2bSsstefan1   void initializeRuntimeFunctions() {
3807cfd267cSsstefan1     Module &M = *((*ModuleSlice.begin())->getParent());
3817cfd267cSsstefan1 
3826aab27baSsstefan1     // Helper macros for handling __VA_ARGS__ in OMP_RTL
3836aab27baSsstefan1 #define OMP_TYPE(VarName, ...)                                                 \
3846aab27baSsstefan1   Type *VarName = OMPBuilder.VarName;                                          \
3856aab27baSsstefan1   (void)VarName;
3866aab27baSsstefan1 
3876aab27baSsstefan1 #define OMP_ARRAY_TYPE(VarName, ...)                                           \
3886aab27baSsstefan1   ArrayType *VarName##Ty = OMPBuilder.VarName##Ty;                             \
3896aab27baSsstefan1   (void)VarName##Ty;                                                           \
3906aab27baSsstefan1   PointerType *VarName##PtrTy = OMPBuilder.VarName##PtrTy;                     \
3916aab27baSsstefan1   (void)VarName##PtrTy;
3926aab27baSsstefan1 
3936aab27baSsstefan1 #define OMP_FUNCTION_TYPE(VarName, ...)                                        \
3946aab27baSsstefan1   FunctionType *VarName = OMPBuilder.VarName;                                  \
3956aab27baSsstefan1   (void)VarName;                                                               \
3966aab27baSsstefan1   PointerType *VarName##Ptr = OMPBuilder.VarName##Ptr;                         \
3976aab27baSsstefan1   (void)VarName##Ptr;
3986aab27baSsstefan1 
3996aab27baSsstefan1 #define OMP_STRUCT_TYPE(VarName, ...)                                          \
4006aab27baSsstefan1   StructType *VarName = OMPBuilder.VarName;                                    \
4016aab27baSsstefan1   (void)VarName;                                                               \
4026aab27baSsstefan1   PointerType *VarName##Ptr = OMPBuilder.VarName##Ptr;                         \
4036aab27baSsstefan1   (void)VarName##Ptr;
4046aab27baSsstefan1 
4057cfd267cSsstefan1 #define OMP_RTL(_Enum, _Name, _IsVarArg, _ReturnType, ...)                     \
4067cfd267cSsstefan1   {                                                                            \
4077cfd267cSsstefan1     SmallVector<Type *, 8> ArgsTypes({__VA_ARGS__});                           \
4087cfd267cSsstefan1     Function *F = M.getFunction(_Name);                                        \
409eef6601bSJoseph Huber     RTLFunctions.insert(F);                                                    \
4106aab27baSsstefan1     if (declMatchesRTFTypes(F, OMPBuilder._ReturnType, ArgsTypes)) {           \
411d9659bf6SJohannes Doerfert       RuntimeFunctionIDMap[F] = _Enum;                                         \
4127cfd267cSsstefan1       auto &RFI = RFIs[_Enum];                                                 \
4137cfd267cSsstefan1       RFI.Kind = _Enum;                                                        \
4147cfd267cSsstefan1       RFI.Name = _Name;                                                        \
4157cfd267cSsstefan1       RFI.IsVarArg = _IsVarArg;                                                \
4166aab27baSsstefan1       RFI.ReturnType = OMPBuilder._ReturnType;                                 \
4177cfd267cSsstefan1       RFI.ArgumentTypes = std::move(ArgsTypes);                                \
4187cfd267cSsstefan1       RFI.Declaration = F;                                                     \
419b8235d2bSsstefan1       unsigned NumUses = collectUses(RFI);                                     \
4207cfd267cSsstefan1       (void)NumUses;                                                           \
4217cfd267cSsstefan1       LLVM_DEBUG({                                                             \
4227cfd267cSsstefan1         dbgs() << TAG << RFI.Name << (RFI.Declaration ? "" : " not")           \
4237cfd267cSsstefan1                << " found\n";                                                  \
4247cfd267cSsstefan1         if (RFI.Declaration)                                                   \
4257cfd267cSsstefan1           dbgs() << TAG << "-> got " << NumUses << " uses in "                 \
4267cfd267cSsstefan1                  << RFI.getNumFunctionsWithUses()                              \
4277cfd267cSsstefan1                  << " different functions.\n";                                 \
4287cfd267cSsstefan1       });                                                                      \
4297cfd267cSsstefan1     }                                                                          \
4307cfd267cSsstefan1   }
4317cfd267cSsstefan1 #include "llvm/Frontend/OpenMP/OMPKinds.def"
4327cfd267cSsstefan1 
4337cfd267cSsstefan1     // TODO: We should attach the attributes defined in OMPKinds.def.
4347cfd267cSsstefan1   }
435e8039ad4SJohannes Doerfert 
436e8039ad4SJohannes Doerfert   /// Collection of known kernels (\see Kernel) in the module.
437e8039ad4SJohannes Doerfert   SmallPtrSetImpl<Kernel> &Kernels;
438eef6601bSJoseph Huber 
439eef6601bSJoseph Huber   /// Collection of known OpenMP runtime functions..
440eef6601bSJoseph Huber   DenseSet<const Function *> RTLFunctions;
4417cfd267cSsstefan1 };
4427cfd267cSsstefan1 
443d9659bf6SJohannes Doerfert template <typename Ty, bool InsertInvalidates = true>
444d9659bf6SJohannes Doerfert struct BooleanStateWithPtrSetVector : public BooleanState {
445d9659bf6SJohannes Doerfert 
446d9659bf6SJohannes Doerfert   bool contains(Ty *Elem) const { return Set.contains(Elem); }
447d9659bf6SJohannes Doerfert   bool insert(Ty *Elem) {
448d9659bf6SJohannes Doerfert     if (InsertInvalidates)
449d9659bf6SJohannes Doerfert       BooleanState::indicatePessimisticFixpoint();
450d9659bf6SJohannes Doerfert     return Set.insert(Elem);
451d9659bf6SJohannes Doerfert   }
452d9659bf6SJohannes Doerfert 
453d9659bf6SJohannes Doerfert   Ty *operator[](int Idx) const { return Set[Idx]; }
454d9659bf6SJohannes Doerfert   bool operator==(const BooleanStateWithPtrSetVector &RHS) const {
455d9659bf6SJohannes Doerfert     return BooleanState::operator==(RHS) && Set == RHS.Set;
456d9659bf6SJohannes Doerfert   }
457d9659bf6SJohannes Doerfert   bool operator!=(const BooleanStateWithPtrSetVector &RHS) const {
458d9659bf6SJohannes Doerfert     return !(*this == RHS);
459d9659bf6SJohannes Doerfert   }
460d9659bf6SJohannes Doerfert 
461d9659bf6SJohannes Doerfert   bool empty() const { return Set.empty(); }
462d9659bf6SJohannes Doerfert   size_t size() const { return Set.size(); }
463d9659bf6SJohannes Doerfert 
464d9659bf6SJohannes Doerfert   /// "Clamp" this state with \p RHS.
465d9659bf6SJohannes Doerfert   BooleanStateWithPtrSetVector &
466d9659bf6SJohannes Doerfert   operator^=(const BooleanStateWithPtrSetVector &RHS) {
467d9659bf6SJohannes Doerfert     BooleanState::operator^=(RHS);
468d9659bf6SJohannes Doerfert     Set.insert(RHS.Set.begin(), RHS.Set.end());
469d9659bf6SJohannes Doerfert     return *this;
470d9659bf6SJohannes Doerfert   }
471d9659bf6SJohannes Doerfert 
472d9659bf6SJohannes Doerfert private:
473d9659bf6SJohannes Doerfert   /// A set to keep track of elements.
474d9659bf6SJohannes Doerfert   SetVector<Ty *> Set;
475d9659bf6SJohannes Doerfert 
476d9659bf6SJohannes Doerfert public:
477d9659bf6SJohannes Doerfert   typename decltype(Set)::iterator begin() { return Set.begin(); }
478d9659bf6SJohannes Doerfert   typename decltype(Set)::iterator end() { return Set.end(); }
479d9659bf6SJohannes Doerfert   typename decltype(Set)::const_iterator begin() const { return Set.begin(); }
480d9659bf6SJohannes Doerfert   typename decltype(Set)::const_iterator end() const { return Set.end(); }
481d9659bf6SJohannes Doerfert };
482d9659bf6SJohannes Doerfert 
483d9659bf6SJohannes Doerfert struct KernelInfoState : AbstractState {
484d9659bf6SJohannes Doerfert   /// Flag to track if we reached a fixpoint.
485d9659bf6SJohannes Doerfert   bool IsAtFixpoint = false;
486d9659bf6SJohannes Doerfert 
487d9659bf6SJohannes Doerfert   /// The parallel regions (identified by the outlined parallel functions) that
488d9659bf6SJohannes Doerfert   /// can be reached from the associated function.
489d9659bf6SJohannes Doerfert   BooleanStateWithPtrSetVector<Function, /* InsertInvalidates */ false>
490d9659bf6SJohannes Doerfert       ReachedKnownParallelRegions;
491d9659bf6SJohannes Doerfert 
492d9659bf6SJohannes Doerfert   /// State to track what parallel region we might reach.
493d9659bf6SJohannes Doerfert   BooleanStateWithPtrSetVector<CallBase> ReachedUnknownParallelRegions;
494d9659bf6SJohannes Doerfert 
495514c033dSJohannes Doerfert   /// State to track if we are in SPMD-mode, assumed or know, and why we decided
496e8439ec8SGiorgis Georgakoudis   /// we cannot be. If it is assumed, then RequiresFullRuntime should also be
497e8439ec8SGiorgis Georgakoudis   /// false.
498514c033dSJohannes Doerfert   BooleanStateWithPtrSetVector<Instruction> SPMDCompatibilityTracker;
499514c033dSJohannes Doerfert 
500d9659bf6SJohannes Doerfert   /// The __kmpc_target_init call in this kernel, if any. If we find more than
501d9659bf6SJohannes Doerfert   /// one we abort as the kernel is malformed.
502d9659bf6SJohannes Doerfert   CallBase *KernelInitCB = nullptr;
503d9659bf6SJohannes Doerfert 
504d9659bf6SJohannes Doerfert   /// The __kmpc_target_deinit call in this kernel, if any. If we find more than
505d9659bf6SJohannes Doerfert   /// one we abort as the kernel is malformed.
506d9659bf6SJohannes Doerfert   CallBase *KernelDeinitCB = nullptr;
507d9659bf6SJohannes Doerfert 
508ca662297SShilei Tian   /// Flag to indicate if the associated function is a kernel entry.
509ca662297SShilei Tian   bool IsKernelEntry = false;
510ca662297SShilei Tian 
511ca662297SShilei Tian   /// State to track what kernel entries can reach the associated function.
512ca662297SShilei Tian   BooleanStateWithPtrSetVector<Function, false> ReachingKernelEntries;
513ca662297SShilei Tian 
514d9659bf6SJohannes Doerfert   /// Abstract State interface
515d9659bf6SJohannes Doerfert   ///{
516d9659bf6SJohannes Doerfert 
517d9659bf6SJohannes Doerfert   KernelInfoState() {}
518d9659bf6SJohannes Doerfert   KernelInfoState(bool BestState) {
519d9659bf6SJohannes Doerfert     if (!BestState)
520d9659bf6SJohannes Doerfert       indicatePessimisticFixpoint();
521d9659bf6SJohannes Doerfert   }
522d9659bf6SJohannes Doerfert 
523d9659bf6SJohannes Doerfert   /// See AbstractState::isValidState(...)
524d9659bf6SJohannes Doerfert   bool isValidState() const override { return true; }
525d9659bf6SJohannes Doerfert 
526d9659bf6SJohannes Doerfert   /// See AbstractState::isAtFixpoint(...)
527d9659bf6SJohannes Doerfert   bool isAtFixpoint() const override { return IsAtFixpoint; }
528d9659bf6SJohannes Doerfert 
529d9659bf6SJohannes Doerfert   /// See AbstractState::indicatePessimisticFixpoint(...)
530d9659bf6SJohannes Doerfert   ChangeStatus indicatePessimisticFixpoint() override {
531d9659bf6SJohannes Doerfert     IsAtFixpoint = true;
532514c033dSJohannes Doerfert     SPMDCompatibilityTracker.indicatePessimisticFixpoint();
533d9659bf6SJohannes Doerfert     ReachedUnknownParallelRegions.indicatePessimisticFixpoint();
534d9659bf6SJohannes Doerfert     return ChangeStatus::CHANGED;
535d9659bf6SJohannes Doerfert   }
536d9659bf6SJohannes Doerfert 
537d9659bf6SJohannes Doerfert   /// See AbstractState::indicateOptimisticFixpoint(...)
538d9659bf6SJohannes Doerfert   ChangeStatus indicateOptimisticFixpoint() override {
539d9659bf6SJohannes Doerfert     IsAtFixpoint = true;
540d9659bf6SJohannes Doerfert     return ChangeStatus::UNCHANGED;
541d9659bf6SJohannes Doerfert   }
542d9659bf6SJohannes Doerfert 
543d9659bf6SJohannes Doerfert   /// Return the assumed state
544d9659bf6SJohannes Doerfert   KernelInfoState &getAssumed() { return *this; }
545d9659bf6SJohannes Doerfert   const KernelInfoState &getAssumed() const { return *this; }
546d9659bf6SJohannes Doerfert 
547d9659bf6SJohannes Doerfert   bool operator==(const KernelInfoState &RHS) const {
548514c033dSJohannes Doerfert     if (SPMDCompatibilityTracker != RHS.SPMDCompatibilityTracker)
549514c033dSJohannes Doerfert       return false;
550d9659bf6SJohannes Doerfert     if (ReachedKnownParallelRegions != RHS.ReachedKnownParallelRegions)
551d9659bf6SJohannes Doerfert       return false;
552d9659bf6SJohannes Doerfert     if (ReachedUnknownParallelRegions != RHS.ReachedUnknownParallelRegions)
553d9659bf6SJohannes Doerfert       return false;
554ca662297SShilei Tian     if (ReachingKernelEntries != RHS.ReachingKernelEntries)
555ca662297SShilei Tian       return false;
556d9659bf6SJohannes Doerfert     return true;
557d9659bf6SJohannes Doerfert   }
558d9659bf6SJohannes Doerfert 
559d9659bf6SJohannes Doerfert   /// Return empty set as the best state of potential values.
560d9659bf6SJohannes Doerfert   static KernelInfoState getBestState() { return KernelInfoState(true); }
561d9659bf6SJohannes Doerfert 
562d9659bf6SJohannes Doerfert   static KernelInfoState getBestState(KernelInfoState &KIS) {
563d9659bf6SJohannes Doerfert     return getBestState();
564d9659bf6SJohannes Doerfert   }
565d9659bf6SJohannes Doerfert 
566d9659bf6SJohannes Doerfert   /// Return full set as the worst state of potential values.
567d9659bf6SJohannes Doerfert   static KernelInfoState getWorstState() { return KernelInfoState(false); }
568d9659bf6SJohannes Doerfert 
569d9659bf6SJohannes Doerfert   /// "Clamp" this state with \p KIS.
570d9659bf6SJohannes Doerfert   KernelInfoState operator^=(const KernelInfoState &KIS) {
571d9659bf6SJohannes Doerfert     // Do not merge two different _init and _deinit call sites.
572d9659bf6SJohannes Doerfert     if (KIS.KernelInitCB) {
573d9659bf6SJohannes Doerfert       if (KernelInitCB && KernelInitCB != KIS.KernelInitCB)
574d9659bf6SJohannes Doerfert         indicatePessimisticFixpoint();
575d9659bf6SJohannes Doerfert       KernelInitCB = KIS.KernelInitCB;
576d9659bf6SJohannes Doerfert     }
577d9659bf6SJohannes Doerfert     if (KIS.KernelDeinitCB) {
578d9659bf6SJohannes Doerfert       if (KernelDeinitCB && KernelDeinitCB != KIS.KernelDeinitCB)
579d9659bf6SJohannes Doerfert         indicatePessimisticFixpoint();
580d9659bf6SJohannes Doerfert       KernelDeinitCB = KIS.KernelDeinitCB;
581d9659bf6SJohannes Doerfert     }
582514c033dSJohannes Doerfert     SPMDCompatibilityTracker ^= KIS.SPMDCompatibilityTracker;
583d9659bf6SJohannes Doerfert     ReachedKnownParallelRegions ^= KIS.ReachedKnownParallelRegions;
584d9659bf6SJohannes Doerfert     ReachedUnknownParallelRegions ^= KIS.ReachedUnknownParallelRegions;
585d9659bf6SJohannes Doerfert     return *this;
586d9659bf6SJohannes Doerfert   }
587d9659bf6SJohannes Doerfert 
588d9659bf6SJohannes Doerfert   KernelInfoState operator&=(const KernelInfoState &KIS) {
589d9659bf6SJohannes Doerfert     return (*this ^= KIS);
590d9659bf6SJohannes Doerfert   }
591d9659bf6SJohannes Doerfert 
592d9659bf6SJohannes Doerfert   ///}
593d9659bf6SJohannes Doerfert };
594d9659bf6SJohannes Doerfert 
5958931add6SHamilton Tobon Mosquera /// Used to map the values physically (in the IR) stored in an offload
5968931add6SHamilton Tobon Mosquera /// array, to a vector in memory.
5978931add6SHamilton Tobon Mosquera struct OffloadArray {
5988931add6SHamilton Tobon Mosquera   /// Physical array (in the IR).
5998931add6SHamilton Tobon Mosquera   AllocaInst *Array = nullptr;
6008931add6SHamilton Tobon Mosquera   /// Mapped values.
6018931add6SHamilton Tobon Mosquera   SmallVector<Value *, 8> StoredValues;
6028931add6SHamilton Tobon Mosquera   /// Last stores made in the offload array.
6038931add6SHamilton Tobon Mosquera   SmallVector<StoreInst *, 8> LastAccesses;
6048931add6SHamilton Tobon Mosquera 
6058931add6SHamilton Tobon Mosquera   OffloadArray() = default;
6068931add6SHamilton Tobon Mosquera 
6078931add6SHamilton Tobon Mosquera   /// Initializes the OffloadArray with the values stored in \p Array before
6088931add6SHamilton Tobon Mosquera   /// instruction \p Before is reached. Returns false if the initialization
6098931add6SHamilton Tobon Mosquera   /// fails.
6108931add6SHamilton Tobon Mosquera   /// This MUST be used immediately after the construction of the object.
6118931add6SHamilton Tobon Mosquera   bool initialize(AllocaInst &Array, Instruction &Before) {
6128931add6SHamilton Tobon Mosquera     if (!Array.getAllocatedType()->isArrayTy())
6138931add6SHamilton Tobon Mosquera       return false;
6148931add6SHamilton Tobon Mosquera 
6158931add6SHamilton Tobon Mosquera     if (!getValues(Array, Before))
6168931add6SHamilton Tobon Mosquera       return false;
6178931add6SHamilton Tobon Mosquera 
6188931add6SHamilton Tobon Mosquera     this->Array = &Array;
6198931add6SHamilton Tobon Mosquera     return true;
6208931add6SHamilton Tobon Mosquera   }
6218931add6SHamilton Tobon Mosquera 
622da8bec47SJoseph Huber   static const unsigned DeviceIDArgNum = 1;
623da8bec47SJoseph Huber   static const unsigned BasePtrsArgNum = 3;
624da8bec47SJoseph Huber   static const unsigned PtrsArgNum = 4;
625da8bec47SJoseph Huber   static const unsigned SizesArgNum = 5;
6261d3d9b9cSHamilton Tobon Mosquera 
6278931add6SHamilton Tobon Mosquera private:
6288931add6SHamilton Tobon Mosquera   /// Traverses the BasicBlock where \p Array is, collecting the stores made to
6298931add6SHamilton Tobon Mosquera   /// \p Array, leaving StoredValues with the values stored before the
6308931add6SHamilton Tobon Mosquera   /// instruction \p Before is reached.
6318931add6SHamilton Tobon Mosquera   bool getValues(AllocaInst &Array, Instruction &Before) {
6328931add6SHamilton Tobon Mosquera     // Initialize container.
633d08d490aSJohannes Doerfert     const uint64_t NumValues = Array.getAllocatedType()->getArrayNumElements();
6348931add6SHamilton Tobon Mosquera     StoredValues.assign(NumValues, nullptr);
6358931add6SHamilton Tobon Mosquera     LastAccesses.assign(NumValues, nullptr);
6368931add6SHamilton Tobon Mosquera 
6378931add6SHamilton Tobon Mosquera     // TODO: This assumes the instruction \p Before is in the same
6388931add6SHamilton Tobon Mosquera     //  BasicBlock as Array. Make it general, for any control flow graph.
6398931add6SHamilton Tobon Mosquera     BasicBlock *BB = Array.getParent();
6408931add6SHamilton Tobon Mosquera     if (BB != Before.getParent())
6418931add6SHamilton Tobon Mosquera       return false;
6428931add6SHamilton Tobon Mosquera 
6438931add6SHamilton Tobon Mosquera     const DataLayout &DL = Array.getModule()->getDataLayout();
6448931add6SHamilton Tobon Mosquera     const unsigned int PointerSize = DL.getPointerSize();
6458931add6SHamilton Tobon Mosquera 
6468931add6SHamilton Tobon Mosquera     for (Instruction &I : *BB) {
6478931add6SHamilton Tobon Mosquera       if (&I == &Before)
6488931add6SHamilton Tobon Mosquera         break;
6498931add6SHamilton Tobon Mosquera 
6508931add6SHamilton Tobon Mosquera       if (!isa<StoreInst>(&I))
6518931add6SHamilton Tobon Mosquera         continue;
6528931add6SHamilton Tobon Mosquera 
6538931add6SHamilton Tobon Mosquera       auto *S = cast<StoreInst>(&I);
6548931add6SHamilton Tobon Mosquera       int64_t Offset = -1;
655d08d490aSJohannes Doerfert       auto *Dst =
656d08d490aSJohannes Doerfert           GetPointerBaseWithConstantOffset(S->getPointerOperand(), Offset, DL);
6578931add6SHamilton Tobon Mosquera       if (Dst == &Array) {
6588931add6SHamilton Tobon Mosquera         int64_t Idx = Offset / PointerSize;
6598931add6SHamilton Tobon Mosquera         StoredValues[Idx] = getUnderlyingObject(S->getValueOperand());
6608931add6SHamilton Tobon Mosquera         LastAccesses[Idx] = S;
6618931add6SHamilton Tobon Mosquera       }
6628931add6SHamilton Tobon Mosquera     }
6638931add6SHamilton Tobon Mosquera 
6648931add6SHamilton Tobon Mosquera     return isFilled();
6658931add6SHamilton Tobon Mosquera   }
6668931add6SHamilton Tobon Mosquera 
6678931add6SHamilton Tobon Mosquera   /// Returns true if all values in StoredValues and
6688931add6SHamilton Tobon Mosquera   /// LastAccesses are not nullptrs.
6698931add6SHamilton Tobon Mosquera   bool isFilled() {
6708931add6SHamilton Tobon Mosquera     const unsigned NumValues = StoredValues.size();
6718931add6SHamilton Tobon Mosquera     for (unsigned I = 0; I < NumValues; ++I) {
6728931add6SHamilton Tobon Mosquera       if (!StoredValues[I] || !LastAccesses[I])
6738931add6SHamilton Tobon Mosquera         return false;
6748931add6SHamilton Tobon Mosquera     }
6758931add6SHamilton Tobon Mosquera 
6768931add6SHamilton Tobon Mosquera     return true;
6778931add6SHamilton Tobon Mosquera   }
6788931add6SHamilton Tobon Mosquera };
6798931add6SHamilton Tobon Mosquera 
6807cfd267cSsstefan1 struct OpenMPOpt {
6817cfd267cSsstefan1 
6827cfd267cSsstefan1   using OptimizationRemarkGetter =
6837cfd267cSsstefan1       function_ref<OptimizationRemarkEmitter &(Function *)>;
6847cfd267cSsstefan1 
6857cfd267cSsstefan1   OpenMPOpt(SmallVectorImpl<Function *> &SCC, CallGraphUpdater &CGUpdater,
6867cfd267cSsstefan1             OptimizationRemarkGetter OREGetter,
687b8235d2bSsstefan1             OMPInformationCache &OMPInfoCache, Attributor &A)
68877b79d79SMehdi Amini       : M(*(*SCC.begin())->getParent()), SCC(SCC), CGUpdater(CGUpdater),
689b8235d2bSsstefan1         OREGetter(OREGetter), OMPInfoCache(OMPInfoCache), A(A) {}
6907cfd267cSsstefan1 
691a2281419SJoseph Huber   /// Check if any remarks are enabled for openmp-opt
692a2281419SJoseph Huber   bool remarksEnabled() {
693a2281419SJoseph Huber     auto &Ctx = M.getContext();
694a2281419SJoseph Huber     return Ctx.getDiagHandlerPtr()->isAnyRemarkEnabled(DEBUG_TYPE);
695a2281419SJoseph Huber   }
696a2281419SJoseph Huber 
6979548b74aSJohannes Doerfert   /// Run all OpenMP optimizations on the underlying SCC/ModuleSlice.
698b2ad63d3SJoseph Huber   bool run(bool IsModulePass) {
69954bd3751SJohannes Doerfert     if (SCC.empty())
70054bd3751SJohannes Doerfert       return false;
70154bd3751SJohannes Doerfert 
7029548b74aSJohannes Doerfert     bool Changed = false;
7039548b74aSJohannes Doerfert 
7049548b74aSJohannes Doerfert     LLVM_DEBUG(dbgs() << TAG << "Run on SCC with " << SCC.size()
70577b79d79SMehdi Amini                       << " functions in a slice with "
70677b79d79SMehdi Amini                       << OMPInfoCache.ModuleSlice.size() << " functions\n");
7079548b74aSJohannes Doerfert 
708b2ad63d3SJoseph Huber     if (IsModulePass) {
709d9659bf6SJohannes Doerfert       Changed |= runAttributor(IsModulePass);
71018283125SJoseph Huber 
7116fc51c9fSJoseph Huber       // Recollect uses, in case Attributor deleted any.
7126fc51c9fSJoseph Huber       OMPInfoCache.recollectUses();
7136fc51c9fSJoseph Huber 
714b2ad63d3SJoseph Huber       if (remarksEnabled())
715b2ad63d3SJoseph Huber         analysisGlobalization();
716b2ad63d3SJoseph Huber     } else {
717e8039ad4SJohannes Doerfert       if (PrintICVValues)
718e8039ad4SJohannes Doerfert         printICVs();
719e8039ad4SJohannes Doerfert       if (PrintOpenMPKernels)
720e8039ad4SJohannes Doerfert         printKernels();
721e8039ad4SJohannes Doerfert 
722d9659bf6SJohannes Doerfert       Changed |= runAttributor(IsModulePass);
723e8039ad4SJohannes Doerfert 
724e8039ad4SJohannes Doerfert       // Recollect uses, in case Attributor deleted any.
725e8039ad4SJohannes Doerfert       OMPInfoCache.recollectUses();
726e8039ad4SJohannes Doerfert 
727e8039ad4SJohannes Doerfert       Changed |= deleteParallelRegions();
728d9659bf6SJohannes Doerfert       Changed |= rewriteDeviceCodeStateMachine();
729d9659bf6SJohannes Doerfert 
730496f8e5bSHamilton Tobon Mosquera       if (HideMemoryTransferLatency)
731496f8e5bSHamilton Tobon Mosquera         Changed |= hideMemTransfersLatency();
7323a6bfcf2SGiorgis Georgakoudis       Changed |= deduplicateRuntimeCalls();
7333a6bfcf2SGiorgis Georgakoudis       if (EnableParallelRegionMerging) {
7343a6bfcf2SGiorgis Georgakoudis         if (mergeParallelRegions()) {
7353a6bfcf2SGiorgis Georgakoudis           deduplicateRuntimeCalls();
7363a6bfcf2SGiorgis Georgakoudis           Changed = true;
7373a6bfcf2SGiorgis Georgakoudis         }
7383a6bfcf2SGiorgis Georgakoudis       }
739b2ad63d3SJoseph Huber     }
740e8039ad4SJohannes Doerfert 
741e8039ad4SJohannes Doerfert     return Changed;
742e8039ad4SJohannes Doerfert   }
743e8039ad4SJohannes Doerfert 
7440f426935Ssstefan1   /// Print initial ICV values for testing.
7450f426935Ssstefan1   /// FIXME: This should be done from the Attributor once it is added.
746e8039ad4SJohannes Doerfert   void printICVs() const {
747cb9cfa0dSsstefan1     InternalControlVar ICVs[] = {ICV_nthreads, ICV_active_levels, ICV_cancel,
748cb9cfa0dSsstefan1                                  ICV_proc_bind};
7490f426935Ssstefan1 
7500f426935Ssstefan1     for (Function *F : OMPInfoCache.ModuleSlice) {
7510f426935Ssstefan1       for (auto ICV : ICVs) {
7520f426935Ssstefan1         auto ICVInfo = OMPInfoCache.ICVs[ICV];
7532db182ffSJoseph Huber         auto Remark = [&](OptimizationRemarkAnalysis ORA) {
7542db182ffSJoseph Huber           return ORA << "OpenMP ICV " << ore::NV("OpenMPICV", ICVInfo.Name)
7550f426935Ssstefan1                      << " Value: "
7560f426935Ssstefan1                      << (ICVInfo.InitValue
75761cdaf66SSimon Pilgrim                              ? toString(ICVInfo.InitValue->getValue(), 10, true)
7580f426935Ssstefan1                              : "IMPLEMENTATION_DEFINED");
7590f426935Ssstefan1         };
7600f426935Ssstefan1 
7612db182ffSJoseph Huber         emitRemark<OptimizationRemarkAnalysis>(F, "OpenMPICVTracker", Remark);
7620f426935Ssstefan1       }
7630f426935Ssstefan1     }
7640f426935Ssstefan1   }
7650f426935Ssstefan1 
766e8039ad4SJohannes Doerfert   /// Print OpenMP GPU kernels for testing.
767e8039ad4SJohannes Doerfert   void printKernels() const {
768e8039ad4SJohannes Doerfert     for (Function *F : SCC) {
769e8039ad4SJohannes Doerfert       if (!OMPInfoCache.Kernels.count(F))
770e8039ad4SJohannes Doerfert         continue;
771b8235d2bSsstefan1 
7722db182ffSJoseph Huber       auto Remark = [&](OptimizationRemarkAnalysis ORA) {
7732db182ffSJoseph Huber         return ORA << "OpenMP GPU kernel "
774e8039ad4SJohannes Doerfert                    << ore::NV("OpenMPGPUKernel", F->getName()) << "\n";
775e8039ad4SJohannes Doerfert       };
776b8235d2bSsstefan1 
7772db182ffSJoseph Huber       emitRemark<OptimizationRemarkAnalysis>(F, "OpenMPGPU", Remark);
778e8039ad4SJohannes Doerfert     }
7799548b74aSJohannes Doerfert   }
7809548b74aSJohannes Doerfert 
7817cfd267cSsstefan1   /// Return the call if \p U is a callee use in a regular call. If \p RFI is
7827cfd267cSsstefan1   /// given it has to be the callee or a nullptr is returned.
7837cfd267cSsstefan1   static CallInst *getCallIfRegularCall(
7847cfd267cSsstefan1       Use &U, OMPInformationCache::RuntimeFunctionInfo *RFI = nullptr) {
7857cfd267cSsstefan1     CallInst *CI = dyn_cast<CallInst>(U.getUser());
7867cfd267cSsstefan1     if (CI && CI->isCallee(&U) && !CI->hasOperandBundles() &&
7877cfd267cSsstefan1         (!RFI || CI->getCalledFunction() == RFI->Declaration))
7887cfd267cSsstefan1       return CI;
7897cfd267cSsstefan1     return nullptr;
7907cfd267cSsstefan1   }
7917cfd267cSsstefan1 
7927cfd267cSsstefan1   /// Return the call if \p V is a regular call. If \p RFI is given it has to be
7937cfd267cSsstefan1   /// the callee or a nullptr is returned.
7947cfd267cSsstefan1   static CallInst *getCallIfRegularCall(
7957cfd267cSsstefan1       Value &V, OMPInformationCache::RuntimeFunctionInfo *RFI = nullptr) {
7967cfd267cSsstefan1     CallInst *CI = dyn_cast<CallInst>(&V);
7977cfd267cSsstefan1     if (CI && !CI->hasOperandBundles() &&
7987cfd267cSsstefan1         (!RFI || CI->getCalledFunction() == RFI->Declaration))
7997cfd267cSsstefan1       return CI;
8007cfd267cSsstefan1     return nullptr;
8017cfd267cSsstefan1   }
8027cfd267cSsstefan1 
8039548b74aSJohannes Doerfert private:
8043a6bfcf2SGiorgis Georgakoudis   /// Merge parallel regions when it is safe.
8053a6bfcf2SGiorgis Georgakoudis   bool mergeParallelRegions() {
8063a6bfcf2SGiorgis Georgakoudis     const unsigned CallbackCalleeOperand = 2;
8073a6bfcf2SGiorgis Georgakoudis     const unsigned CallbackFirstArgOperand = 3;
8083a6bfcf2SGiorgis Georgakoudis     using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
8093a6bfcf2SGiorgis Georgakoudis 
8103a6bfcf2SGiorgis Georgakoudis     // Check if there are any __kmpc_fork_call calls to merge.
8113a6bfcf2SGiorgis Georgakoudis     OMPInformationCache::RuntimeFunctionInfo &RFI =
8123a6bfcf2SGiorgis Georgakoudis         OMPInfoCache.RFIs[OMPRTL___kmpc_fork_call];
8133a6bfcf2SGiorgis Georgakoudis 
8143a6bfcf2SGiorgis Georgakoudis     if (!RFI.Declaration)
8153a6bfcf2SGiorgis Georgakoudis       return false;
8163a6bfcf2SGiorgis Georgakoudis 
81797517055SGiorgis Georgakoudis     // Unmergable calls that prevent merging a parallel region.
81897517055SGiorgis Georgakoudis     OMPInformationCache::RuntimeFunctionInfo UnmergableCallsInfo[] = {
81997517055SGiorgis Georgakoudis         OMPInfoCache.RFIs[OMPRTL___kmpc_push_proc_bind],
82097517055SGiorgis Georgakoudis         OMPInfoCache.RFIs[OMPRTL___kmpc_push_num_threads],
82197517055SGiorgis Georgakoudis     };
8223a6bfcf2SGiorgis Georgakoudis 
8233a6bfcf2SGiorgis Georgakoudis     bool Changed = false;
8243a6bfcf2SGiorgis Georgakoudis     LoopInfo *LI = nullptr;
8253a6bfcf2SGiorgis Georgakoudis     DominatorTree *DT = nullptr;
8263a6bfcf2SGiorgis Georgakoudis 
8273a6bfcf2SGiorgis Georgakoudis     SmallDenseMap<BasicBlock *, SmallPtrSet<Instruction *, 4>> BB2PRMap;
8283a6bfcf2SGiorgis Georgakoudis 
8293a6bfcf2SGiorgis Georgakoudis     BasicBlock *StartBB = nullptr, *EndBB = nullptr;
8303a6bfcf2SGiorgis Georgakoudis     auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
8313a6bfcf2SGiorgis Georgakoudis                          BasicBlock &ContinuationIP) {
8323a6bfcf2SGiorgis Georgakoudis       BasicBlock *CGStartBB = CodeGenIP.getBlock();
8333a6bfcf2SGiorgis Georgakoudis       BasicBlock *CGEndBB =
8343a6bfcf2SGiorgis Georgakoudis           SplitBlock(CGStartBB, &*CodeGenIP.getPoint(), DT, LI);
8353a6bfcf2SGiorgis Georgakoudis       assert(StartBB != nullptr && "StartBB should not be null");
8363a6bfcf2SGiorgis Georgakoudis       CGStartBB->getTerminator()->setSuccessor(0, StartBB);
8373a6bfcf2SGiorgis Georgakoudis       assert(EndBB != nullptr && "EndBB should not be null");
8383a6bfcf2SGiorgis Georgakoudis       EndBB->getTerminator()->setSuccessor(0, CGEndBB);
8393a6bfcf2SGiorgis Georgakoudis     };
8403a6bfcf2SGiorgis Georgakoudis 
841240dd924SAlex Zinenko     auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, Value &,
842240dd924SAlex Zinenko                       Value &Inner, Value *&ReplacementValue) -> InsertPointTy {
843240dd924SAlex Zinenko       ReplacementValue = &Inner;
8443a6bfcf2SGiorgis Georgakoudis       return CodeGenIP;
8453a6bfcf2SGiorgis Georgakoudis     };
8463a6bfcf2SGiorgis Georgakoudis 
8473a6bfcf2SGiorgis Georgakoudis     auto FiniCB = [&](InsertPointTy CodeGenIP) {};
8483a6bfcf2SGiorgis Georgakoudis 
84997517055SGiorgis Georgakoudis     /// Create a sequential execution region within a merged parallel region,
85097517055SGiorgis Georgakoudis     /// encapsulated in a master construct with a barrier for synchronization.
85197517055SGiorgis Georgakoudis     auto CreateSequentialRegion = [&](Function *OuterFn,
85297517055SGiorgis Georgakoudis                                       BasicBlock *OuterPredBB,
85397517055SGiorgis Georgakoudis                                       Instruction *SeqStartI,
85497517055SGiorgis Georgakoudis                                       Instruction *SeqEndI) {
85597517055SGiorgis Georgakoudis       // Isolate the instructions of the sequential region to a separate
85697517055SGiorgis Georgakoudis       // block.
85797517055SGiorgis Georgakoudis       BasicBlock *ParentBB = SeqStartI->getParent();
85897517055SGiorgis Georgakoudis       BasicBlock *SeqEndBB =
85997517055SGiorgis Georgakoudis           SplitBlock(ParentBB, SeqEndI->getNextNode(), DT, LI);
86097517055SGiorgis Georgakoudis       BasicBlock *SeqAfterBB =
86197517055SGiorgis Georgakoudis           SplitBlock(SeqEndBB, &*SeqEndBB->getFirstInsertionPt(), DT, LI);
86297517055SGiorgis Georgakoudis       BasicBlock *SeqStartBB =
86397517055SGiorgis Georgakoudis           SplitBlock(ParentBB, SeqStartI, DT, LI, nullptr, "seq.par.merged");
86497517055SGiorgis Georgakoudis 
86597517055SGiorgis Georgakoudis       assert(ParentBB->getUniqueSuccessor() == SeqStartBB &&
86697517055SGiorgis Georgakoudis              "Expected a different CFG");
86797517055SGiorgis Georgakoudis       const DebugLoc DL = ParentBB->getTerminator()->getDebugLoc();
86897517055SGiorgis Georgakoudis       ParentBB->getTerminator()->eraseFromParent();
86997517055SGiorgis Georgakoudis 
87097517055SGiorgis Georgakoudis       auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
87197517055SGiorgis Georgakoudis                            BasicBlock &ContinuationIP) {
87297517055SGiorgis Georgakoudis         BasicBlock *CGStartBB = CodeGenIP.getBlock();
87397517055SGiorgis Georgakoudis         BasicBlock *CGEndBB =
87497517055SGiorgis Georgakoudis             SplitBlock(CGStartBB, &*CodeGenIP.getPoint(), DT, LI);
87597517055SGiorgis Georgakoudis         assert(SeqStartBB != nullptr && "SeqStartBB should not be null");
87697517055SGiorgis Georgakoudis         CGStartBB->getTerminator()->setSuccessor(0, SeqStartBB);
87797517055SGiorgis Georgakoudis         assert(SeqEndBB != nullptr && "SeqEndBB should not be null");
87897517055SGiorgis Georgakoudis         SeqEndBB->getTerminator()->setSuccessor(0, CGEndBB);
87997517055SGiorgis Georgakoudis       };
88097517055SGiorgis Georgakoudis       auto FiniCB = [&](InsertPointTy CodeGenIP) {};
88197517055SGiorgis Georgakoudis 
88297517055SGiorgis Georgakoudis       // Find outputs from the sequential region to outside users and
88397517055SGiorgis Georgakoudis       // broadcast their values to them.
88497517055SGiorgis Georgakoudis       for (Instruction &I : *SeqStartBB) {
88597517055SGiorgis Georgakoudis         SmallPtrSet<Instruction *, 4> OutsideUsers;
88697517055SGiorgis Georgakoudis         for (User *Usr : I.users()) {
88797517055SGiorgis Georgakoudis           Instruction &UsrI = *cast<Instruction>(Usr);
88897517055SGiorgis Georgakoudis           // Ignore outputs to LT intrinsics, code extraction for the merged
88997517055SGiorgis Georgakoudis           // parallel region will fix them.
89097517055SGiorgis Georgakoudis           if (UsrI.isLifetimeStartOrEnd())
89197517055SGiorgis Georgakoudis             continue;
89297517055SGiorgis Georgakoudis 
89397517055SGiorgis Georgakoudis           if (UsrI.getParent() != SeqStartBB)
89497517055SGiorgis Georgakoudis             OutsideUsers.insert(&UsrI);
89597517055SGiorgis Georgakoudis         }
89697517055SGiorgis Georgakoudis 
89797517055SGiorgis Georgakoudis         if (OutsideUsers.empty())
89897517055SGiorgis Georgakoudis           continue;
89997517055SGiorgis Georgakoudis 
90097517055SGiorgis Georgakoudis         // Emit an alloca in the outer region to store the broadcasted
90197517055SGiorgis Georgakoudis         // value.
90297517055SGiorgis Georgakoudis         const DataLayout &DL = M.getDataLayout();
90397517055SGiorgis Georgakoudis         AllocaInst *AllocaI = new AllocaInst(
90497517055SGiorgis Georgakoudis             I.getType(), DL.getAllocaAddrSpace(), nullptr,
90597517055SGiorgis Georgakoudis             I.getName() + ".seq.output.alloc", &OuterFn->front().front());
90697517055SGiorgis Georgakoudis 
90797517055SGiorgis Georgakoudis         // Emit a store instruction in the sequential BB to update the
90897517055SGiorgis Georgakoudis         // value.
90997517055SGiorgis Georgakoudis         new StoreInst(&I, AllocaI, SeqStartBB->getTerminator());
91097517055SGiorgis Georgakoudis 
91197517055SGiorgis Georgakoudis         // Emit a load instruction and replace the use of the output value
91297517055SGiorgis Georgakoudis         // with it.
91397517055SGiorgis Georgakoudis         for (Instruction *UsrI : OutsideUsers) {
9145b70c12fSJohannes Doerfert           LoadInst *LoadI = new LoadInst(
9155b70c12fSJohannes Doerfert               I.getType(), AllocaI, I.getName() + ".seq.output.load", UsrI);
91697517055SGiorgis Georgakoudis           UsrI->replaceUsesOfWith(&I, LoadI);
91797517055SGiorgis Georgakoudis         }
91897517055SGiorgis Georgakoudis       }
91997517055SGiorgis Georgakoudis 
92097517055SGiorgis Georgakoudis       OpenMPIRBuilder::LocationDescription Loc(
92197517055SGiorgis Georgakoudis           InsertPointTy(ParentBB, ParentBB->end()), DL);
92297517055SGiorgis Georgakoudis       InsertPointTy SeqAfterIP =
92397517055SGiorgis Georgakoudis           OMPInfoCache.OMPBuilder.createMaster(Loc, BodyGenCB, FiniCB);
92497517055SGiorgis Georgakoudis 
92597517055SGiorgis Georgakoudis       OMPInfoCache.OMPBuilder.createBarrier(SeqAfterIP, OMPD_parallel);
92697517055SGiorgis Georgakoudis 
92797517055SGiorgis Georgakoudis       BranchInst::Create(SeqAfterBB, SeqAfterIP.getBlock());
92897517055SGiorgis Georgakoudis 
92997517055SGiorgis Georgakoudis       LLVM_DEBUG(dbgs() << TAG << "After sequential inlining " << *OuterFn
93097517055SGiorgis Georgakoudis                         << "\n");
93197517055SGiorgis Georgakoudis     };
93297517055SGiorgis Georgakoudis 
9333a6bfcf2SGiorgis Georgakoudis     // Helper to merge the __kmpc_fork_call calls in MergableCIs. They are all
9343a6bfcf2SGiorgis Georgakoudis     // contained in BB and only separated by instructions that can be
9353a6bfcf2SGiorgis Georgakoudis     // redundantly executed in parallel. The block BB is split before the first
9363a6bfcf2SGiorgis Georgakoudis     // call (in MergableCIs) and after the last so the entire region we merge
9373a6bfcf2SGiorgis Georgakoudis     // into a single parallel region is contained in a single basic block
9383a6bfcf2SGiorgis Georgakoudis     // without any other instructions. We use the OpenMPIRBuilder to outline
9393a6bfcf2SGiorgis Georgakoudis     // that block and call the resulting function via __kmpc_fork_call.
9403a6bfcf2SGiorgis Georgakoudis     auto Merge = [&](SmallVectorImpl<CallInst *> &MergableCIs, BasicBlock *BB) {
9413a6bfcf2SGiorgis Georgakoudis       // TODO: Change the interface to allow single CIs expanded, e.g, to
9423a6bfcf2SGiorgis Georgakoudis       // include an outer loop.
9433a6bfcf2SGiorgis Georgakoudis       assert(MergableCIs.size() > 1 && "Assumed multiple mergable CIs");
9443a6bfcf2SGiorgis Georgakoudis 
9453a6bfcf2SGiorgis Georgakoudis       auto Remark = [&](OptimizationRemark OR) {
946eef6601bSJoseph Huber         OR << "Parallel region merged with parallel region"
947eef6601bSJoseph Huber            << (MergableCIs.size() > 2 ? "s" : "") << " at ";
94823b0ab2aSKazu Hirata         for (auto *CI : llvm::drop_begin(MergableCIs)) {
9493a6bfcf2SGiorgis Georgakoudis           OR << ore::NV("OpenMPParallelMerge", CI->getDebugLoc());
9503a6bfcf2SGiorgis Georgakoudis           if (CI != MergableCIs.back())
9513a6bfcf2SGiorgis Georgakoudis             OR << ", ";
9523a6bfcf2SGiorgis Georgakoudis         }
953eef6601bSJoseph Huber         return OR << ".";
9543a6bfcf2SGiorgis Georgakoudis       };
9553a6bfcf2SGiorgis Georgakoudis 
9562c31d5ebSJoseph Huber       emitRemark<OptimizationRemark>(MergableCIs.front(), "OMP150", Remark);
9573a6bfcf2SGiorgis Georgakoudis 
9583a6bfcf2SGiorgis Georgakoudis       Function *OriginalFn = BB->getParent();
9593a6bfcf2SGiorgis Georgakoudis       LLVM_DEBUG(dbgs() << TAG << "Merge " << MergableCIs.size()
9603a6bfcf2SGiorgis Georgakoudis                         << " parallel regions in " << OriginalFn->getName()
9613a6bfcf2SGiorgis Georgakoudis                         << "\n");
9623a6bfcf2SGiorgis Georgakoudis 
9633a6bfcf2SGiorgis Georgakoudis       // Isolate the calls to merge in a separate block.
9643a6bfcf2SGiorgis Georgakoudis       EndBB = SplitBlock(BB, MergableCIs.back()->getNextNode(), DT, LI);
9653a6bfcf2SGiorgis Georgakoudis       BasicBlock *AfterBB =
9663a6bfcf2SGiorgis Georgakoudis           SplitBlock(EndBB, &*EndBB->getFirstInsertionPt(), DT, LI);
9673a6bfcf2SGiorgis Georgakoudis       StartBB = SplitBlock(BB, MergableCIs.front(), DT, LI, nullptr,
9683a6bfcf2SGiorgis Georgakoudis                            "omp.par.merged");
9693a6bfcf2SGiorgis Georgakoudis 
9703a6bfcf2SGiorgis Georgakoudis       assert(BB->getUniqueSuccessor() == StartBB && "Expected a different CFG");
9713a6bfcf2SGiorgis Georgakoudis       const DebugLoc DL = BB->getTerminator()->getDebugLoc();
9723a6bfcf2SGiorgis Georgakoudis       BB->getTerminator()->eraseFromParent();
9733a6bfcf2SGiorgis Georgakoudis 
97497517055SGiorgis Georgakoudis       // Create sequential regions for sequential instructions that are
97597517055SGiorgis Georgakoudis       // in-between mergable parallel regions.
97697517055SGiorgis Georgakoudis       for (auto *It = MergableCIs.begin(), *End = MergableCIs.end() - 1;
97797517055SGiorgis Georgakoudis            It != End; ++It) {
97897517055SGiorgis Georgakoudis         Instruction *ForkCI = *It;
97997517055SGiorgis Georgakoudis         Instruction *NextForkCI = *(It + 1);
98097517055SGiorgis Georgakoudis 
98197517055SGiorgis Georgakoudis         // Continue if there are not in-between instructions.
98297517055SGiorgis Georgakoudis         if (ForkCI->getNextNode() == NextForkCI)
98397517055SGiorgis Georgakoudis           continue;
98497517055SGiorgis Georgakoudis 
98597517055SGiorgis Georgakoudis         CreateSequentialRegion(OriginalFn, BB, ForkCI->getNextNode(),
98697517055SGiorgis Georgakoudis                                NextForkCI->getPrevNode());
98797517055SGiorgis Georgakoudis       }
98897517055SGiorgis Georgakoudis 
9893a6bfcf2SGiorgis Georgakoudis       OpenMPIRBuilder::LocationDescription Loc(InsertPointTy(BB, BB->end()),
9903a6bfcf2SGiorgis Georgakoudis                                                DL);
9913a6bfcf2SGiorgis Georgakoudis       IRBuilder<>::InsertPoint AllocaIP(
9923a6bfcf2SGiorgis Georgakoudis           &OriginalFn->getEntryBlock(),
9933a6bfcf2SGiorgis Georgakoudis           OriginalFn->getEntryBlock().getFirstInsertionPt());
9943a6bfcf2SGiorgis Georgakoudis       // Create the merged parallel region with default proc binding, to
9953a6bfcf2SGiorgis Georgakoudis       // avoid overriding binding settings, and without explicit cancellation.
996e5dba2d7SMichael Kruse       InsertPointTy AfterIP = OMPInfoCache.OMPBuilder.createParallel(
9973a6bfcf2SGiorgis Georgakoudis           Loc, AllocaIP, BodyGenCB, PrivCB, FiniCB, nullptr, nullptr,
9983a6bfcf2SGiorgis Georgakoudis           OMP_PROC_BIND_default, /* IsCancellable */ false);
9993a6bfcf2SGiorgis Georgakoudis       BranchInst::Create(AfterBB, AfterIP.getBlock());
10003a6bfcf2SGiorgis Georgakoudis 
10013a6bfcf2SGiorgis Georgakoudis       // Perform the actual outlining.
1002b1191206SMichael Kruse       OMPInfoCache.OMPBuilder.finalize(OriginalFn,
1003b1191206SMichael Kruse                                        /* AllowExtractorSinking */ true);
10043a6bfcf2SGiorgis Georgakoudis 
10053a6bfcf2SGiorgis Georgakoudis       Function *OutlinedFn = MergableCIs.front()->getCaller();
10063a6bfcf2SGiorgis Georgakoudis 
10073a6bfcf2SGiorgis Georgakoudis       // Replace the __kmpc_fork_call calls with direct calls to the outlined
10083a6bfcf2SGiorgis Georgakoudis       // callbacks.
10093a6bfcf2SGiorgis Georgakoudis       SmallVector<Value *, 8> Args;
10103a6bfcf2SGiorgis Georgakoudis       for (auto *CI : MergableCIs) {
10113a6bfcf2SGiorgis Georgakoudis         Value *Callee =
10123a6bfcf2SGiorgis Georgakoudis             CI->getArgOperand(CallbackCalleeOperand)->stripPointerCasts();
10133a6bfcf2SGiorgis Georgakoudis         FunctionType *FT =
10143a6bfcf2SGiorgis Georgakoudis             cast<FunctionType>(Callee->getType()->getPointerElementType());
10153a6bfcf2SGiorgis Georgakoudis         Args.clear();
10163a6bfcf2SGiorgis Georgakoudis         Args.push_back(OutlinedFn->getArg(0));
10173a6bfcf2SGiorgis Georgakoudis         Args.push_back(OutlinedFn->getArg(1));
10183a6bfcf2SGiorgis Georgakoudis         for (unsigned U = CallbackFirstArgOperand, E = CI->getNumArgOperands();
10193a6bfcf2SGiorgis Georgakoudis              U < E; ++U)
10203a6bfcf2SGiorgis Georgakoudis           Args.push_back(CI->getArgOperand(U));
10213a6bfcf2SGiorgis Georgakoudis 
10223a6bfcf2SGiorgis Georgakoudis         CallInst *NewCI = CallInst::Create(FT, Callee, Args, "", CI);
10233a6bfcf2SGiorgis Georgakoudis         if (CI->getDebugLoc())
10243a6bfcf2SGiorgis Georgakoudis           NewCI->setDebugLoc(CI->getDebugLoc());
10253a6bfcf2SGiorgis Georgakoudis 
10263a6bfcf2SGiorgis Georgakoudis         // Forward parameter attributes from the callback to the callee.
10273a6bfcf2SGiorgis Georgakoudis         for (unsigned U = CallbackFirstArgOperand, E = CI->getNumArgOperands();
10283a6bfcf2SGiorgis Georgakoudis              U < E; ++U)
10293a6bfcf2SGiorgis Georgakoudis           for (const Attribute &A : CI->getAttributes().getParamAttributes(U))
10303a6bfcf2SGiorgis Georgakoudis             NewCI->addParamAttr(
10313a6bfcf2SGiorgis Georgakoudis                 U - (CallbackFirstArgOperand - CallbackCalleeOperand), A);
10323a6bfcf2SGiorgis Georgakoudis 
10333a6bfcf2SGiorgis Georgakoudis         // Emit an explicit barrier to replace the implicit fork-join barrier.
10343a6bfcf2SGiorgis Georgakoudis         if (CI != MergableCIs.back()) {
10353a6bfcf2SGiorgis Georgakoudis           // TODO: Remove barrier if the merged parallel region includes the
10363a6bfcf2SGiorgis Georgakoudis           // 'nowait' clause.
1037e5dba2d7SMichael Kruse           OMPInfoCache.OMPBuilder.createBarrier(
10383a6bfcf2SGiorgis Georgakoudis               InsertPointTy(NewCI->getParent(),
10393a6bfcf2SGiorgis Georgakoudis                             NewCI->getNextNode()->getIterator()),
10403a6bfcf2SGiorgis Georgakoudis               OMPD_parallel);
10413a6bfcf2SGiorgis Georgakoudis         }
10423a6bfcf2SGiorgis Georgakoudis 
10433a6bfcf2SGiorgis Georgakoudis         CI->eraseFromParent();
10443a6bfcf2SGiorgis Georgakoudis       }
10453a6bfcf2SGiorgis Georgakoudis 
10463a6bfcf2SGiorgis Georgakoudis       assert(OutlinedFn != OriginalFn && "Outlining failed");
10477fea561eSArthur Eubanks       CGUpdater.registerOutlinedFunction(*OriginalFn, *OutlinedFn);
10483a6bfcf2SGiorgis Georgakoudis       CGUpdater.reanalyzeFunction(*OriginalFn);
10493a6bfcf2SGiorgis Georgakoudis 
10503a6bfcf2SGiorgis Georgakoudis       NumOpenMPParallelRegionsMerged += MergableCIs.size();
10513a6bfcf2SGiorgis Georgakoudis 
10523a6bfcf2SGiorgis Georgakoudis       return true;
10533a6bfcf2SGiorgis Georgakoudis     };
10543a6bfcf2SGiorgis Georgakoudis 
10553a6bfcf2SGiorgis Georgakoudis     // Helper function that identifes sequences of
10563a6bfcf2SGiorgis Georgakoudis     // __kmpc_fork_call uses in a basic block.
10573a6bfcf2SGiorgis Georgakoudis     auto DetectPRsCB = [&](Use &U, Function &F) {
10583a6bfcf2SGiorgis Georgakoudis       CallInst *CI = getCallIfRegularCall(U, &RFI);
10593a6bfcf2SGiorgis Georgakoudis       BB2PRMap[CI->getParent()].insert(CI);
10603a6bfcf2SGiorgis Georgakoudis 
10613a6bfcf2SGiorgis Georgakoudis       return false;
10623a6bfcf2SGiorgis Georgakoudis     };
10633a6bfcf2SGiorgis Georgakoudis 
10643a6bfcf2SGiorgis Georgakoudis     BB2PRMap.clear();
10653a6bfcf2SGiorgis Georgakoudis     RFI.foreachUse(SCC, DetectPRsCB);
10663a6bfcf2SGiorgis Georgakoudis     SmallVector<SmallVector<CallInst *, 4>, 4> MergableCIsVector;
10673a6bfcf2SGiorgis Georgakoudis     // Find mergable parallel regions within a basic block that are
10683a6bfcf2SGiorgis Georgakoudis     // safe to merge, that is any in-between instructions can safely
10693a6bfcf2SGiorgis Georgakoudis     // execute in parallel after merging.
10703a6bfcf2SGiorgis Georgakoudis     // TODO: support merging across basic-blocks.
10713a6bfcf2SGiorgis Georgakoudis     for (auto &It : BB2PRMap) {
10723a6bfcf2SGiorgis Georgakoudis       auto &CIs = It.getSecond();
10733a6bfcf2SGiorgis Georgakoudis       if (CIs.size() < 2)
10743a6bfcf2SGiorgis Georgakoudis         continue;
10753a6bfcf2SGiorgis Georgakoudis 
10763a6bfcf2SGiorgis Georgakoudis       BasicBlock *BB = It.getFirst();
10773a6bfcf2SGiorgis Georgakoudis       SmallVector<CallInst *, 4> MergableCIs;
10783a6bfcf2SGiorgis Georgakoudis 
107997517055SGiorgis Georgakoudis       /// Returns true if the instruction is mergable, false otherwise.
108097517055SGiorgis Georgakoudis       /// A terminator instruction is unmergable by definition since merging
108197517055SGiorgis Georgakoudis       /// works within a BB. Instructions before the mergable region are
108297517055SGiorgis Georgakoudis       /// mergable if they are not calls to OpenMP runtime functions that may
108397517055SGiorgis Georgakoudis       /// set different execution parameters for subsequent parallel regions.
108497517055SGiorgis Georgakoudis       /// Instructions in-between parallel regions are mergable if they are not
108597517055SGiorgis Georgakoudis       /// calls to any non-intrinsic function since that may call a non-mergable
108697517055SGiorgis Georgakoudis       /// OpenMP runtime function.
108797517055SGiorgis Georgakoudis       auto IsMergable = [&](Instruction &I, bool IsBeforeMergableRegion) {
108897517055SGiorgis Georgakoudis         // We do not merge across BBs, hence return false (unmergable) if the
108997517055SGiorgis Georgakoudis         // instruction is a terminator.
109097517055SGiorgis Georgakoudis         if (I.isTerminator())
109197517055SGiorgis Georgakoudis           return false;
109297517055SGiorgis Georgakoudis 
109397517055SGiorgis Georgakoudis         if (!isa<CallInst>(&I))
109497517055SGiorgis Georgakoudis           return true;
109597517055SGiorgis Georgakoudis 
109697517055SGiorgis Georgakoudis         CallInst *CI = cast<CallInst>(&I);
109797517055SGiorgis Georgakoudis         if (IsBeforeMergableRegion) {
109897517055SGiorgis Georgakoudis           Function *CalledFunction = CI->getCalledFunction();
109997517055SGiorgis Georgakoudis           if (!CalledFunction)
110097517055SGiorgis Georgakoudis             return false;
110197517055SGiorgis Georgakoudis           // Return false (unmergable) if the call before the parallel
110297517055SGiorgis Georgakoudis           // region calls an explicit affinity (proc_bind) or number of
110397517055SGiorgis Georgakoudis           // threads (num_threads) compiler-generated function. Those settings
110497517055SGiorgis Georgakoudis           // may be incompatible with following parallel regions.
110597517055SGiorgis Georgakoudis           // TODO: ICV tracking to detect compatibility.
110697517055SGiorgis Georgakoudis           for (const auto &RFI : UnmergableCallsInfo) {
110797517055SGiorgis Georgakoudis             if (CalledFunction == RFI.Declaration)
110897517055SGiorgis Georgakoudis               return false;
110997517055SGiorgis Georgakoudis           }
111097517055SGiorgis Georgakoudis         } else {
111197517055SGiorgis Georgakoudis           // Return false (unmergable) if there is a call instruction
111297517055SGiorgis Georgakoudis           // in-between parallel regions when it is not an intrinsic. It
111397517055SGiorgis Georgakoudis           // may call an unmergable OpenMP runtime function in its callpath.
111497517055SGiorgis Georgakoudis           // TODO: Keep track of possible OpenMP calls in the callpath.
111597517055SGiorgis Georgakoudis           if (!isa<IntrinsicInst>(CI))
111697517055SGiorgis Georgakoudis             return false;
111797517055SGiorgis Georgakoudis         }
111897517055SGiorgis Georgakoudis 
111997517055SGiorgis Georgakoudis         return true;
112097517055SGiorgis Georgakoudis       };
11213a6bfcf2SGiorgis Georgakoudis       // Find maximal number of parallel region CIs that are safe to merge.
112297517055SGiorgis Georgakoudis       for (auto It = BB->begin(), End = BB->end(); It != End;) {
112397517055SGiorgis Georgakoudis         Instruction &I = *It;
112497517055SGiorgis Georgakoudis         ++It;
112597517055SGiorgis Georgakoudis 
11263a6bfcf2SGiorgis Georgakoudis         if (CIs.count(&I)) {
11273a6bfcf2SGiorgis Georgakoudis           MergableCIs.push_back(cast<CallInst>(&I));
11283a6bfcf2SGiorgis Georgakoudis           continue;
11293a6bfcf2SGiorgis Georgakoudis         }
11303a6bfcf2SGiorgis Georgakoudis 
113197517055SGiorgis Georgakoudis         // Continue expanding if the instruction is mergable.
113297517055SGiorgis Georgakoudis         if (IsMergable(I, MergableCIs.empty()))
11333a6bfcf2SGiorgis Georgakoudis           continue;
11343a6bfcf2SGiorgis Georgakoudis 
113597517055SGiorgis Georgakoudis         // Forward the instruction iterator to skip the next parallel region
113697517055SGiorgis Georgakoudis         // since there is an unmergable instruction which can affect it.
113797517055SGiorgis Georgakoudis         for (; It != End; ++It) {
113897517055SGiorgis Georgakoudis           Instruction &SkipI = *It;
113997517055SGiorgis Georgakoudis           if (CIs.count(&SkipI)) {
114097517055SGiorgis Georgakoudis             LLVM_DEBUG(dbgs() << TAG << "Skip parallel region " << SkipI
114197517055SGiorgis Georgakoudis                               << " due to " << I << "\n");
114297517055SGiorgis Georgakoudis             ++It;
114397517055SGiorgis Georgakoudis             break;
114497517055SGiorgis Georgakoudis           }
114597517055SGiorgis Georgakoudis         }
114697517055SGiorgis Georgakoudis 
114797517055SGiorgis Georgakoudis         // Store mergable regions found.
11483a6bfcf2SGiorgis Georgakoudis         if (MergableCIs.size() > 1) {
11493a6bfcf2SGiorgis Georgakoudis           MergableCIsVector.push_back(MergableCIs);
11503a6bfcf2SGiorgis Georgakoudis           LLVM_DEBUG(dbgs() << TAG << "Found " << MergableCIs.size()
11513a6bfcf2SGiorgis Georgakoudis                             << " parallel regions in block " << BB->getName()
11523a6bfcf2SGiorgis Georgakoudis                             << " of function " << BB->getParent()->getName()
11533a6bfcf2SGiorgis Georgakoudis                             << "\n";);
11543a6bfcf2SGiorgis Georgakoudis         }
11553a6bfcf2SGiorgis Georgakoudis 
11563a6bfcf2SGiorgis Georgakoudis         MergableCIs.clear();
11573a6bfcf2SGiorgis Georgakoudis       }
11583a6bfcf2SGiorgis Georgakoudis 
11593a6bfcf2SGiorgis Georgakoudis       if (!MergableCIsVector.empty()) {
11603a6bfcf2SGiorgis Georgakoudis         Changed = true;
11613a6bfcf2SGiorgis Georgakoudis 
11623a6bfcf2SGiorgis Georgakoudis         for (auto &MergableCIs : MergableCIsVector)
11633a6bfcf2SGiorgis Georgakoudis           Merge(MergableCIs, BB);
1164b2ad63d3SJoseph Huber         MergableCIsVector.clear();
11653a6bfcf2SGiorgis Georgakoudis       }
11663a6bfcf2SGiorgis Georgakoudis     }
11673a6bfcf2SGiorgis Georgakoudis 
11683a6bfcf2SGiorgis Georgakoudis     if (Changed) {
116997517055SGiorgis Georgakoudis       /// Re-collect use for fork calls, emitted barrier calls, and
117097517055SGiorgis Georgakoudis       /// any emitted master/end_master calls.
117197517055SGiorgis Georgakoudis       OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_fork_call);
117297517055SGiorgis Georgakoudis       OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_barrier);
117397517055SGiorgis Georgakoudis       OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_master);
117497517055SGiorgis Georgakoudis       OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_end_master);
11753a6bfcf2SGiorgis Georgakoudis     }
11763a6bfcf2SGiorgis Georgakoudis 
11773a6bfcf2SGiorgis Georgakoudis     return Changed;
11783a6bfcf2SGiorgis Georgakoudis   }
11793a6bfcf2SGiorgis Georgakoudis 
11809d38f98dSJohannes Doerfert   /// Try to delete parallel regions if possible.
1181e565db49SJohannes Doerfert   bool deleteParallelRegions() {
1182e565db49SJohannes Doerfert     const unsigned CallbackCalleeOperand = 2;
1183e565db49SJohannes Doerfert 
11847cfd267cSsstefan1     OMPInformationCache::RuntimeFunctionInfo &RFI =
11857cfd267cSsstefan1         OMPInfoCache.RFIs[OMPRTL___kmpc_fork_call];
11867cfd267cSsstefan1 
1187e565db49SJohannes Doerfert     if (!RFI.Declaration)
1188e565db49SJohannes Doerfert       return false;
1189e565db49SJohannes Doerfert 
1190e565db49SJohannes Doerfert     bool Changed = false;
1191e565db49SJohannes Doerfert     auto DeleteCallCB = [&](Use &U, Function &) {
1192e565db49SJohannes Doerfert       CallInst *CI = getCallIfRegularCall(U);
1193e565db49SJohannes Doerfert       if (!CI)
1194e565db49SJohannes Doerfert         return false;
1195e565db49SJohannes Doerfert       auto *Fn = dyn_cast<Function>(
1196e565db49SJohannes Doerfert           CI->getArgOperand(CallbackCalleeOperand)->stripPointerCasts());
1197e565db49SJohannes Doerfert       if (!Fn)
1198e565db49SJohannes Doerfert         return false;
1199e565db49SJohannes Doerfert       if (!Fn->onlyReadsMemory())
1200e565db49SJohannes Doerfert         return false;
1201e565db49SJohannes Doerfert       if (!Fn->hasFnAttribute(Attribute::WillReturn))
1202e565db49SJohannes Doerfert         return false;
1203e565db49SJohannes Doerfert 
1204e565db49SJohannes Doerfert       LLVM_DEBUG(dbgs() << TAG << "Delete read-only parallel region in "
1205e565db49SJohannes Doerfert                         << CI->getCaller()->getName() << "\n");
12064d4ea9acSHuber, Joseph 
12074d4ea9acSHuber, Joseph       auto Remark = [&](OptimizationRemark OR) {
1208eef6601bSJoseph Huber         return OR << "Removing parallel region with no side-effects.";
12094d4ea9acSHuber, Joseph       };
12102c31d5ebSJoseph Huber       emitRemark<OptimizationRemark>(CI, "OMP160", Remark);
12114d4ea9acSHuber, Joseph 
1212e565db49SJohannes Doerfert       CGUpdater.removeCallSite(*CI);
1213e565db49SJohannes Doerfert       CI->eraseFromParent();
1214e565db49SJohannes Doerfert       Changed = true;
121555eb714aSRoman Lebedev       ++NumOpenMPParallelRegionsDeleted;
1216e565db49SJohannes Doerfert       return true;
1217e565db49SJohannes Doerfert     };
1218e565db49SJohannes Doerfert 
1219624d34afSJohannes Doerfert     RFI.foreachUse(SCC, DeleteCallCB);
1220e565db49SJohannes Doerfert 
1221e565db49SJohannes Doerfert     return Changed;
1222e565db49SJohannes Doerfert   }
1223e565db49SJohannes Doerfert 
1224b726c557SJohannes Doerfert   /// Try to eliminate runtime calls by reusing existing ones.
12259548b74aSJohannes Doerfert   bool deduplicateRuntimeCalls() {
12269548b74aSJohannes Doerfert     bool Changed = false;
12279548b74aSJohannes Doerfert 
1228e28936f6SJohannes Doerfert     RuntimeFunction DeduplicableRuntimeCallIDs[] = {
1229e28936f6SJohannes Doerfert         OMPRTL_omp_get_num_threads,
1230e28936f6SJohannes Doerfert         OMPRTL_omp_in_parallel,
1231e28936f6SJohannes Doerfert         OMPRTL_omp_get_cancellation,
1232e28936f6SJohannes Doerfert         OMPRTL_omp_get_thread_limit,
1233e28936f6SJohannes Doerfert         OMPRTL_omp_get_supported_active_levels,
1234e28936f6SJohannes Doerfert         OMPRTL_omp_get_level,
1235e28936f6SJohannes Doerfert         OMPRTL_omp_get_ancestor_thread_num,
1236e28936f6SJohannes Doerfert         OMPRTL_omp_get_team_size,
1237e28936f6SJohannes Doerfert         OMPRTL_omp_get_active_level,
1238e28936f6SJohannes Doerfert         OMPRTL_omp_in_final,
1239e28936f6SJohannes Doerfert         OMPRTL_omp_get_proc_bind,
1240e28936f6SJohannes Doerfert         OMPRTL_omp_get_num_places,
1241e28936f6SJohannes Doerfert         OMPRTL_omp_get_num_procs,
1242e28936f6SJohannes Doerfert         OMPRTL_omp_get_place_num,
1243e28936f6SJohannes Doerfert         OMPRTL_omp_get_partition_num_places,
1244e28936f6SJohannes Doerfert         OMPRTL_omp_get_partition_place_nums};
1245e28936f6SJohannes Doerfert 
1246bc93c2d7SMarek Kurdej     // Global-tid is handled separately.
12479548b74aSJohannes Doerfert     SmallSetVector<Value *, 16> GTIdArgs;
12489548b74aSJohannes Doerfert     collectGlobalThreadIdArguments(GTIdArgs);
12499548b74aSJohannes Doerfert     LLVM_DEBUG(dbgs() << TAG << "Found " << GTIdArgs.size()
12509548b74aSJohannes Doerfert                       << " global thread ID arguments\n");
12519548b74aSJohannes Doerfert 
12529548b74aSJohannes Doerfert     for (Function *F : SCC) {
1253e28936f6SJohannes Doerfert       for (auto DeduplicableRuntimeCallID : DeduplicableRuntimeCallIDs)
12544e29d256Sserge-sans-paille         Changed |= deduplicateRuntimeCalls(
12554e29d256Sserge-sans-paille             *F, OMPInfoCache.RFIs[DeduplicableRuntimeCallID]);
1256e28936f6SJohannes Doerfert 
1257e28936f6SJohannes Doerfert       // __kmpc_global_thread_num is special as we can replace it with an
1258e28936f6SJohannes Doerfert       // argument in enough cases to make it worth trying.
12599548b74aSJohannes Doerfert       Value *GTIdArg = nullptr;
12609548b74aSJohannes Doerfert       for (Argument &Arg : F->args())
12619548b74aSJohannes Doerfert         if (GTIdArgs.count(&Arg)) {
12629548b74aSJohannes Doerfert           GTIdArg = &Arg;
12639548b74aSJohannes Doerfert           break;
12649548b74aSJohannes Doerfert         }
12659548b74aSJohannes Doerfert       Changed |= deduplicateRuntimeCalls(
12667cfd267cSsstefan1           *F, OMPInfoCache.RFIs[OMPRTL___kmpc_global_thread_num], GTIdArg);
12679548b74aSJohannes Doerfert     }
12689548b74aSJohannes Doerfert 
12699548b74aSJohannes Doerfert     return Changed;
12709548b74aSJohannes Doerfert   }
12719548b74aSJohannes Doerfert 
1272496f8e5bSHamilton Tobon Mosquera   /// Tries to hide the latency of runtime calls that involve host to
1273496f8e5bSHamilton Tobon Mosquera   /// device memory transfers by splitting them into their "issue" and "wait"
1274496f8e5bSHamilton Tobon Mosquera   /// versions. The "issue" is moved upwards as much as possible. The "wait" is
1275496f8e5bSHamilton Tobon Mosquera   /// moved downards as much as possible. The "issue" issues the memory transfer
1276496f8e5bSHamilton Tobon Mosquera   /// asynchronously, returning a handle. The "wait" waits in the returned
1277496f8e5bSHamilton Tobon Mosquera   /// handle for the memory transfer to finish.
1278496f8e5bSHamilton Tobon Mosquera   bool hideMemTransfersLatency() {
1279496f8e5bSHamilton Tobon Mosquera     auto &RFI = OMPInfoCache.RFIs[OMPRTL___tgt_target_data_begin_mapper];
1280496f8e5bSHamilton Tobon Mosquera     bool Changed = false;
1281496f8e5bSHamilton Tobon Mosquera     auto SplitMemTransfers = [&](Use &U, Function &Decl) {
1282496f8e5bSHamilton Tobon Mosquera       auto *RTCall = getCallIfRegularCall(U, &RFI);
1283496f8e5bSHamilton Tobon Mosquera       if (!RTCall)
1284496f8e5bSHamilton Tobon Mosquera         return false;
1285496f8e5bSHamilton Tobon Mosquera 
12868931add6SHamilton Tobon Mosquera       OffloadArray OffloadArrays[3];
12878931add6SHamilton Tobon Mosquera       if (!getValuesInOffloadArrays(*RTCall, OffloadArrays))
12888931add6SHamilton Tobon Mosquera         return false;
12898931add6SHamilton Tobon Mosquera 
12908931add6SHamilton Tobon Mosquera       LLVM_DEBUG(dumpValuesInOffloadArrays(OffloadArrays));
12918931add6SHamilton Tobon Mosquera 
1292bd2fa181SHamilton Tobon Mosquera       // TODO: Check if can be moved upwards.
1293bd2fa181SHamilton Tobon Mosquera       bool WasSplit = false;
1294bd2fa181SHamilton Tobon Mosquera       Instruction *WaitMovementPoint = canBeMovedDownwards(*RTCall);
1295bd2fa181SHamilton Tobon Mosquera       if (WaitMovementPoint)
1296bd2fa181SHamilton Tobon Mosquera         WasSplit = splitTargetDataBeginRTC(*RTCall, *WaitMovementPoint);
1297bd2fa181SHamilton Tobon Mosquera 
1298496f8e5bSHamilton Tobon Mosquera       Changed |= WasSplit;
1299496f8e5bSHamilton Tobon Mosquera       return WasSplit;
1300496f8e5bSHamilton Tobon Mosquera     };
1301496f8e5bSHamilton Tobon Mosquera     RFI.foreachUse(SCC, SplitMemTransfers);
1302496f8e5bSHamilton Tobon Mosquera 
1303496f8e5bSHamilton Tobon Mosquera     return Changed;
1304496f8e5bSHamilton Tobon Mosquera   }
1305496f8e5bSHamilton Tobon Mosquera 
1306a2281419SJoseph Huber   void analysisGlobalization() {
13076fc51c9fSJoseph Huber     auto &RFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
130882453e75SJoseph Huber 
130982453e75SJoseph Huber     auto CheckGlobalization = [&](Use &U, Function &Decl) {
1310a2281419SJoseph Huber       if (CallInst *CI = getCallIfRegularCall(U, &RFI)) {
131144feacc7SJoseph Huber         auto Remark = [&](OptimizationRemarkMissed ORM) {
131244feacc7SJoseph Huber           return ORM
1313a2281419SJoseph Huber                  << "Found thread data sharing on the GPU. "
1314a2281419SJoseph Huber                  << "Expect degraded performance due to data globalization.";
1315a2281419SJoseph Huber         };
13162c31d5ebSJoseph Huber         emitRemark<OptimizationRemarkMissed>(CI, "OMP112", Remark);
1317a2281419SJoseph Huber       }
1318a2281419SJoseph Huber 
1319a2281419SJoseph Huber       return false;
1320a2281419SJoseph Huber     };
1321a2281419SJoseph Huber 
132282453e75SJoseph Huber     RFI.foreachUse(SCC, CheckGlobalization);
132382453e75SJoseph Huber   }
1324a2281419SJoseph Huber 
13258931add6SHamilton Tobon Mosquera   /// Maps the values stored in the offload arrays passed as arguments to
13268931add6SHamilton Tobon Mosquera   /// \p RuntimeCall into the offload arrays in \p OAs.
13278931add6SHamilton Tobon Mosquera   bool getValuesInOffloadArrays(CallInst &RuntimeCall,
13288931add6SHamilton Tobon Mosquera                                 MutableArrayRef<OffloadArray> OAs) {
13298931add6SHamilton Tobon Mosquera     assert(OAs.size() == 3 && "Need space for three offload arrays!");
13308931add6SHamilton Tobon Mosquera 
13318931add6SHamilton Tobon Mosquera     // A runtime call that involves memory offloading looks something like:
13328931add6SHamilton Tobon Mosquera     // call void @__tgt_target_data_begin_mapper(arg0, arg1,
13338931add6SHamilton Tobon Mosquera     //   i8** %offload_baseptrs, i8** %offload_ptrs, i64* %offload_sizes,
13348931add6SHamilton Tobon Mosquera     // ...)
13358931add6SHamilton Tobon Mosquera     // So, the idea is to access the allocas that allocate space for these
13368931add6SHamilton Tobon Mosquera     // offload arrays, offload_baseptrs, offload_ptrs, offload_sizes.
13378931add6SHamilton Tobon Mosquera     // Therefore:
13388931add6SHamilton Tobon Mosquera     // i8** %offload_baseptrs.
13391d3d9b9cSHamilton Tobon Mosquera     Value *BasePtrsArg =
13401d3d9b9cSHamilton Tobon Mosquera         RuntimeCall.getArgOperand(OffloadArray::BasePtrsArgNum);
13418931add6SHamilton Tobon Mosquera     // i8** %offload_ptrs.
13421d3d9b9cSHamilton Tobon Mosquera     Value *PtrsArg = RuntimeCall.getArgOperand(OffloadArray::PtrsArgNum);
13438931add6SHamilton Tobon Mosquera     // i8** %offload_sizes.
13441d3d9b9cSHamilton Tobon Mosquera     Value *SizesArg = RuntimeCall.getArgOperand(OffloadArray::SizesArgNum);
13458931add6SHamilton Tobon Mosquera 
13468931add6SHamilton Tobon Mosquera     // Get values stored in **offload_baseptrs.
13478931add6SHamilton Tobon Mosquera     auto *V = getUnderlyingObject(BasePtrsArg);
13488931add6SHamilton Tobon Mosquera     if (!isa<AllocaInst>(V))
13498931add6SHamilton Tobon Mosquera       return false;
13508931add6SHamilton Tobon Mosquera     auto *BasePtrsArray = cast<AllocaInst>(V);
13518931add6SHamilton Tobon Mosquera     if (!OAs[0].initialize(*BasePtrsArray, RuntimeCall))
13528931add6SHamilton Tobon Mosquera       return false;
13538931add6SHamilton Tobon Mosquera 
13548931add6SHamilton Tobon Mosquera     // Get values stored in **offload_baseptrs.
13558931add6SHamilton Tobon Mosquera     V = getUnderlyingObject(PtrsArg);
13568931add6SHamilton Tobon Mosquera     if (!isa<AllocaInst>(V))
13578931add6SHamilton Tobon Mosquera       return false;
13588931add6SHamilton Tobon Mosquera     auto *PtrsArray = cast<AllocaInst>(V);
13598931add6SHamilton Tobon Mosquera     if (!OAs[1].initialize(*PtrsArray, RuntimeCall))
13608931add6SHamilton Tobon Mosquera       return false;
13618931add6SHamilton Tobon Mosquera 
13628931add6SHamilton Tobon Mosquera     // Get values stored in **offload_sizes.
13638931add6SHamilton Tobon Mosquera     V = getUnderlyingObject(SizesArg);
13648931add6SHamilton Tobon Mosquera     // If it's a [constant] global array don't analyze it.
13658931add6SHamilton Tobon Mosquera     if (isa<GlobalValue>(V))
13668931add6SHamilton Tobon Mosquera       return isa<Constant>(V);
13678931add6SHamilton Tobon Mosquera     if (!isa<AllocaInst>(V))
13688931add6SHamilton Tobon Mosquera       return false;
13698931add6SHamilton Tobon Mosquera 
13708931add6SHamilton Tobon Mosquera     auto *SizesArray = cast<AllocaInst>(V);
13718931add6SHamilton Tobon Mosquera     if (!OAs[2].initialize(*SizesArray, RuntimeCall))
13728931add6SHamilton Tobon Mosquera       return false;
13738931add6SHamilton Tobon Mosquera 
13748931add6SHamilton Tobon Mosquera     return true;
13758931add6SHamilton Tobon Mosquera   }
13768931add6SHamilton Tobon Mosquera 
13778931add6SHamilton Tobon Mosquera   /// Prints the values in the OffloadArrays \p OAs using LLVM_DEBUG.
13788931add6SHamilton Tobon Mosquera   /// For now this is a way to test that the function getValuesInOffloadArrays
13798931add6SHamilton Tobon Mosquera   /// is working properly.
13808931add6SHamilton Tobon Mosquera   /// TODO: Move this to a unittest when unittests are available for OpenMPOpt.
13818931add6SHamilton Tobon Mosquera   void dumpValuesInOffloadArrays(ArrayRef<OffloadArray> OAs) {
13828931add6SHamilton Tobon Mosquera     assert(OAs.size() == 3 && "There are three offload arrays to debug!");
13838931add6SHamilton Tobon Mosquera 
13848931add6SHamilton Tobon Mosquera     LLVM_DEBUG(dbgs() << TAG << " Successfully got offload values:\n");
13858931add6SHamilton Tobon Mosquera     std::string ValuesStr;
13868931add6SHamilton Tobon Mosquera     raw_string_ostream Printer(ValuesStr);
13878931add6SHamilton Tobon Mosquera     std::string Separator = " --- ";
13888931add6SHamilton Tobon Mosquera 
13898931add6SHamilton Tobon Mosquera     for (auto *BP : OAs[0].StoredValues) {
13908931add6SHamilton Tobon Mosquera       BP->print(Printer);
13918931add6SHamilton Tobon Mosquera       Printer << Separator;
13928931add6SHamilton Tobon Mosquera     }
13938931add6SHamilton Tobon Mosquera     LLVM_DEBUG(dbgs() << "\t\toffload_baseptrs: " << Printer.str() << "\n");
13948931add6SHamilton Tobon Mosquera     ValuesStr.clear();
13958931add6SHamilton Tobon Mosquera 
13968931add6SHamilton Tobon Mosquera     for (auto *P : OAs[1].StoredValues) {
13978931add6SHamilton Tobon Mosquera       P->print(Printer);
13988931add6SHamilton Tobon Mosquera       Printer << Separator;
13998931add6SHamilton Tobon Mosquera     }
14008931add6SHamilton Tobon Mosquera     LLVM_DEBUG(dbgs() << "\t\toffload_ptrs: " << Printer.str() << "\n");
14018931add6SHamilton Tobon Mosquera     ValuesStr.clear();
14028931add6SHamilton Tobon Mosquera 
14038931add6SHamilton Tobon Mosquera     for (auto *S : OAs[2].StoredValues) {
14048931add6SHamilton Tobon Mosquera       S->print(Printer);
14058931add6SHamilton Tobon Mosquera       Printer << Separator;
14068931add6SHamilton Tobon Mosquera     }
14078931add6SHamilton Tobon Mosquera     LLVM_DEBUG(dbgs() << "\t\toffload_sizes: " << Printer.str() << "\n");
14088931add6SHamilton Tobon Mosquera   }
14098931add6SHamilton Tobon Mosquera 
1410bd2fa181SHamilton Tobon Mosquera   /// Returns the instruction where the "wait" counterpart \p RuntimeCall can be
1411bd2fa181SHamilton Tobon Mosquera   /// moved. Returns nullptr if the movement is not possible, or not worth it.
1412bd2fa181SHamilton Tobon Mosquera   Instruction *canBeMovedDownwards(CallInst &RuntimeCall) {
1413bd2fa181SHamilton Tobon Mosquera     // FIXME: This traverses only the BasicBlock where RuntimeCall is.
1414bd2fa181SHamilton Tobon Mosquera     //  Make it traverse the CFG.
1415bd2fa181SHamilton Tobon Mosquera 
1416bd2fa181SHamilton Tobon Mosquera     Instruction *CurrentI = &RuntimeCall;
1417bd2fa181SHamilton Tobon Mosquera     bool IsWorthIt = false;
1418bd2fa181SHamilton Tobon Mosquera     while ((CurrentI = CurrentI->getNextNode())) {
1419bd2fa181SHamilton Tobon Mosquera 
1420bd2fa181SHamilton Tobon Mosquera       // TODO: Once we detect the regions to be offloaded we should use the
1421bd2fa181SHamilton Tobon Mosquera       //  alias analysis manager to check if CurrentI may modify one of
1422bd2fa181SHamilton Tobon Mosquera       //  the offloaded regions.
1423bd2fa181SHamilton Tobon Mosquera       if (CurrentI->mayHaveSideEffects() || CurrentI->mayReadFromMemory()) {
1424bd2fa181SHamilton Tobon Mosquera         if (IsWorthIt)
1425bd2fa181SHamilton Tobon Mosquera           return CurrentI;
1426bd2fa181SHamilton Tobon Mosquera 
1427bd2fa181SHamilton Tobon Mosquera         return nullptr;
1428bd2fa181SHamilton Tobon Mosquera       }
1429bd2fa181SHamilton Tobon Mosquera 
1430bd2fa181SHamilton Tobon Mosquera       // FIXME: For now if we move it over anything without side effect
1431bd2fa181SHamilton Tobon Mosquera       //  is worth it.
1432bd2fa181SHamilton Tobon Mosquera       IsWorthIt = true;
1433bd2fa181SHamilton Tobon Mosquera     }
1434bd2fa181SHamilton Tobon Mosquera 
1435bd2fa181SHamilton Tobon Mosquera     // Return end of BasicBlock.
1436bd2fa181SHamilton Tobon Mosquera     return RuntimeCall.getParent()->getTerminator();
1437bd2fa181SHamilton Tobon Mosquera   }
1438bd2fa181SHamilton Tobon Mosquera 
1439496f8e5bSHamilton Tobon Mosquera   /// Splits \p RuntimeCall into its "issue" and "wait" counterparts.
1440bd2fa181SHamilton Tobon Mosquera   bool splitTargetDataBeginRTC(CallInst &RuntimeCall,
1441bd2fa181SHamilton Tobon Mosquera                                Instruction &WaitMovementPoint) {
1442bd31abc1SHamilton Tobon Mosquera     // Create stack allocated handle (__tgt_async_info) at the beginning of the
1443bd31abc1SHamilton Tobon Mosquera     // function. Used for storing information of the async transfer, allowing to
1444bd31abc1SHamilton Tobon Mosquera     // wait on it later.
1445496f8e5bSHamilton Tobon Mosquera     auto &IRBuilder = OMPInfoCache.OMPBuilder;
1446bd31abc1SHamilton Tobon Mosquera     auto *F = RuntimeCall.getCaller();
1447bd31abc1SHamilton Tobon Mosquera     Instruction *FirstInst = &(F->getEntryBlock().front());
1448bd31abc1SHamilton Tobon Mosquera     AllocaInst *Handle = new AllocaInst(
1449bd31abc1SHamilton Tobon Mosquera         IRBuilder.AsyncInfo, F->getAddressSpace(), "handle", FirstInst);
1450bd31abc1SHamilton Tobon Mosquera 
1451496f8e5bSHamilton Tobon Mosquera     // Add "issue" runtime call declaration:
1452496f8e5bSHamilton Tobon Mosquera     // declare %struct.tgt_async_info @__tgt_target_data_begin_issue(i64, i32,
1453496f8e5bSHamilton Tobon Mosquera     //   i8**, i8**, i64*, i64*)
1454496f8e5bSHamilton Tobon Mosquera     FunctionCallee IssueDecl = IRBuilder.getOrCreateRuntimeFunction(
1455496f8e5bSHamilton Tobon Mosquera         M, OMPRTL___tgt_target_data_begin_mapper_issue);
1456496f8e5bSHamilton Tobon Mosquera 
1457496f8e5bSHamilton Tobon Mosquera     // Change RuntimeCall call site for its asynchronous version.
145897e55cfeSJoseph Huber     SmallVector<Value *, 16> Args;
1459bd2fa181SHamilton Tobon Mosquera     for (auto &Arg : RuntimeCall.args())
1460496f8e5bSHamilton Tobon Mosquera       Args.push_back(Arg.get());
1461bd31abc1SHamilton Tobon Mosquera     Args.push_back(Handle);
1462496f8e5bSHamilton Tobon Mosquera 
1463496f8e5bSHamilton Tobon Mosquera     CallInst *IssueCallsite =
1464bd31abc1SHamilton Tobon Mosquera         CallInst::Create(IssueDecl, Args, /*NameStr=*/"", &RuntimeCall);
1465bd2fa181SHamilton Tobon Mosquera     RuntimeCall.eraseFromParent();
1466496f8e5bSHamilton Tobon Mosquera 
1467496f8e5bSHamilton Tobon Mosquera     // Add "wait" runtime call declaration:
1468496f8e5bSHamilton Tobon Mosquera     // declare void @__tgt_target_data_begin_wait(i64, %struct.__tgt_async_info)
1469496f8e5bSHamilton Tobon Mosquera     FunctionCallee WaitDecl = IRBuilder.getOrCreateRuntimeFunction(
1470496f8e5bSHamilton Tobon Mosquera         M, OMPRTL___tgt_target_data_begin_mapper_wait);
1471496f8e5bSHamilton Tobon Mosquera 
1472496f8e5bSHamilton Tobon Mosquera     Value *WaitParams[2] = {
1473da8bec47SJoseph Huber         IssueCallsite->getArgOperand(
1474da8bec47SJoseph Huber             OffloadArray::DeviceIDArgNum), // device_id.
1475bd31abc1SHamilton Tobon Mosquera         Handle                             // handle to wait on.
1476496f8e5bSHamilton Tobon Mosquera     };
1477bd2fa181SHamilton Tobon Mosquera     CallInst::Create(WaitDecl, WaitParams, /*NameStr=*/"", &WaitMovementPoint);
1478496f8e5bSHamilton Tobon Mosquera 
1479496f8e5bSHamilton Tobon Mosquera     return true;
1480496f8e5bSHamilton Tobon Mosquera   }
1481496f8e5bSHamilton Tobon Mosquera 
1482dc3b5b00SJohannes Doerfert   static Value *combinedIdentStruct(Value *CurrentIdent, Value *NextIdent,
1483dc3b5b00SJohannes Doerfert                                     bool GlobalOnly, bool &SingleChoice) {
1484dc3b5b00SJohannes Doerfert     if (CurrentIdent == NextIdent)
1485dc3b5b00SJohannes Doerfert       return CurrentIdent;
1486dc3b5b00SJohannes Doerfert 
1487396b7253SJohannes Doerfert     // TODO: Figure out how to actually combine multiple debug locations. For
1488dc3b5b00SJohannes Doerfert     //       now we just keep an existing one if there is a single choice.
1489dc3b5b00SJohannes Doerfert     if (!GlobalOnly || isa<GlobalValue>(NextIdent)) {
1490dc3b5b00SJohannes Doerfert       SingleChoice = !CurrentIdent;
1491dc3b5b00SJohannes Doerfert       return NextIdent;
1492dc3b5b00SJohannes Doerfert     }
1493396b7253SJohannes Doerfert     return nullptr;
1494396b7253SJohannes Doerfert   }
1495396b7253SJohannes Doerfert 
1496396b7253SJohannes Doerfert   /// Return an `struct ident_t*` value that represents the ones used in the
1497396b7253SJohannes Doerfert   /// calls of \p RFI inside of \p F. If \p GlobalOnly is true, we will not
1498396b7253SJohannes Doerfert   /// return a local `struct ident_t*`. For now, if we cannot find a suitable
1499396b7253SJohannes Doerfert   /// return value we create one from scratch. We also do not yet combine
1500396b7253SJohannes Doerfert   /// information, e.g., the source locations, see combinedIdentStruct.
15017cfd267cSsstefan1   Value *
15027cfd267cSsstefan1   getCombinedIdentFromCallUsesIn(OMPInformationCache::RuntimeFunctionInfo &RFI,
15037cfd267cSsstefan1                                  Function &F, bool GlobalOnly) {
1504dc3b5b00SJohannes Doerfert     bool SingleChoice = true;
1505396b7253SJohannes Doerfert     Value *Ident = nullptr;
1506396b7253SJohannes Doerfert     auto CombineIdentStruct = [&](Use &U, Function &Caller) {
1507396b7253SJohannes Doerfert       CallInst *CI = getCallIfRegularCall(U, &RFI);
1508396b7253SJohannes Doerfert       if (!CI || &F != &Caller)
1509396b7253SJohannes Doerfert         return false;
1510396b7253SJohannes Doerfert       Ident = combinedIdentStruct(Ident, CI->getArgOperand(0),
1511dc3b5b00SJohannes Doerfert                                   /* GlobalOnly */ true, SingleChoice);
1512396b7253SJohannes Doerfert       return false;
1513396b7253SJohannes Doerfert     };
1514624d34afSJohannes Doerfert     RFI.foreachUse(SCC, CombineIdentStruct);
1515396b7253SJohannes Doerfert 
1516dc3b5b00SJohannes Doerfert     if (!Ident || !SingleChoice) {
1517396b7253SJohannes Doerfert       // The IRBuilder uses the insertion block to get to the module, this is
1518396b7253SJohannes Doerfert       // unfortunate but we work around it for now.
15197cfd267cSsstefan1       if (!OMPInfoCache.OMPBuilder.getInsertionPoint().getBlock())
15207cfd267cSsstefan1         OMPInfoCache.OMPBuilder.updateToLocation(OpenMPIRBuilder::InsertPointTy(
1521396b7253SJohannes Doerfert             &F.getEntryBlock(), F.getEntryBlock().begin()));
1522396b7253SJohannes Doerfert       // Create a fallback location if non was found.
1523396b7253SJohannes Doerfert       // TODO: Use the debug locations of the calls instead.
15247cfd267cSsstefan1       Constant *Loc = OMPInfoCache.OMPBuilder.getOrCreateDefaultSrcLocStr();
15257cfd267cSsstefan1       Ident = OMPInfoCache.OMPBuilder.getOrCreateIdent(Loc);
1526396b7253SJohannes Doerfert     }
1527396b7253SJohannes Doerfert     return Ident;
1528396b7253SJohannes Doerfert   }
1529396b7253SJohannes Doerfert 
1530b726c557SJohannes Doerfert   /// Try to eliminate calls of \p RFI in \p F by reusing an existing one or
15319548b74aSJohannes Doerfert   /// \p ReplVal if given.
15327cfd267cSsstefan1   bool deduplicateRuntimeCalls(Function &F,
15337cfd267cSsstefan1                                OMPInformationCache::RuntimeFunctionInfo &RFI,
15349548b74aSJohannes Doerfert                                Value *ReplVal = nullptr) {
15358855fec3SJohannes Doerfert     auto *UV = RFI.getUseVector(F);
15368855fec3SJohannes Doerfert     if (!UV || UV->size() + (ReplVal != nullptr) < 2)
1537b1fbf438SRoman Lebedev       return false;
1538b1fbf438SRoman Lebedev 
15397cfd267cSsstefan1     LLVM_DEBUG(
15407cfd267cSsstefan1         dbgs() << TAG << "Deduplicate " << UV->size() << " uses of " << RFI.Name
15417cfd267cSsstefan1                << (ReplVal ? " with an existing value\n" : "\n") << "\n");
15427cfd267cSsstefan1 
1543ab3da5ddSMichael Liao     assert((!ReplVal || (isa<Argument>(ReplVal) &&
1544ab3da5ddSMichael Liao                          cast<Argument>(ReplVal)->getParent() == &F)) &&
15459548b74aSJohannes Doerfert            "Unexpected replacement value!");
1546396b7253SJohannes Doerfert 
1547396b7253SJohannes Doerfert     // TODO: Use dominance to find a good position instead.
15486aab27baSsstefan1     auto CanBeMoved = [this](CallBase &CB) {
1549396b7253SJohannes Doerfert       unsigned NumArgs = CB.getNumArgOperands();
1550396b7253SJohannes Doerfert       if (NumArgs == 0)
1551396b7253SJohannes Doerfert         return true;
15526aab27baSsstefan1       if (CB.getArgOperand(0)->getType() != OMPInfoCache.OMPBuilder.IdentPtr)
1553396b7253SJohannes Doerfert         return false;
1554396b7253SJohannes Doerfert       for (unsigned u = 1; u < NumArgs; ++u)
1555396b7253SJohannes Doerfert         if (isa<Instruction>(CB.getArgOperand(u)))
1556396b7253SJohannes Doerfert           return false;
1557396b7253SJohannes Doerfert       return true;
1558396b7253SJohannes Doerfert     };
1559396b7253SJohannes Doerfert 
15609548b74aSJohannes Doerfert     if (!ReplVal) {
15618855fec3SJohannes Doerfert       for (Use *U : *UV)
15629548b74aSJohannes Doerfert         if (CallInst *CI = getCallIfRegularCall(*U, &RFI)) {
1563396b7253SJohannes Doerfert           if (!CanBeMoved(*CI))
1564396b7253SJohannes Doerfert             continue;
15654d4ea9acSHuber, Joseph 
15669548b74aSJohannes Doerfert           CI->moveBefore(&*F.getEntryBlock().getFirstInsertionPt());
15679548b74aSJohannes Doerfert           ReplVal = CI;
15689548b74aSJohannes Doerfert           break;
15699548b74aSJohannes Doerfert         }
15709548b74aSJohannes Doerfert       if (!ReplVal)
15719548b74aSJohannes Doerfert         return false;
15729548b74aSJohannes Doerfert     }
15739548b74aSJohannes Doerfert 
1574396b7253SJohannes Doerfert     // If we use a call as a replacement value we need to make sure the ident is
1575396b7253SJohannes Doerfert     // valid at the new location. For now we just pick a global one, either
1576396b7253SJohannes Doerfert     // existing and used by one of the calls, or created from scratch.
1577396b7253SJohannes Doerfert     if (CallBase *CI = dyn_cast<CallBase>(ReplVal)) {
1578396b7253SJohannes Doerfert       if (CI->getNumArgOperands() > 0 &&
15796aab27baSsstefan1           CI->getArgOperand(0)->getType() == OMPInfoCache.OMPBuilder.IdentPtr) {
1580396b7253SJohannes Doerfert         Value *Ident = getCombinedIdentFromCallUsesIn(RFI, F,
1581396b7253SJohannes Doerfert                                                       /* GlobalOnly */ true);
1582396b7253SJohannes Doerfert         CI->setArgOperand(0, Ident);
1583396b7253SJohannes Doerfert       }
1584396b7253SJohannes Doerfert     }
1585396b7253SJohannes Doerfert 
15869548b74aSJohannes Doerfert     bool Changed = false;
15879548b74aSJohannes Doerfert     auto ReplaceAndDeleteCB = [&](Use &U, Function &Caller) {
15889548b74aSJohannes Doerfert       CallInst *CI = getCallIfRegularCall(U, &RFI);
15899548b74aSJohannes Doerfert       if (!CI || CI == ReplVal || &F != &Caller)
15909548b74aSJohannes Doerfert         return false;
15919548b74aSJohannes Doerfert       assert(CI->getCaller() == &F && "Unexpected call!");
15924d4ea9acSHuber, Joseph 
15934d4ea9acSHuber, Joseph       auto Remark = [&](OptimizationRemark OR) {
15944d4ea9acSHuber, Joseph         return OR << "OpenMP runtime call "
1595eef6601bSJoseph Huber                   << ore::NV("OpenMPOptRuntime", RFI.Name) << " deduplicated.";
15964d4ea9acSHuber, Joseph       };
1597eef6601bSJoseph Huber       if (CI->getDebugLoc())
15982c31d5ebSJoseph Huber         emitRemark<OptimizationRemark>(CI, "OMP170", Remark);
1599eef6601bSJoseph Huber       else
16002c31d5ebSJoseph Huber         emitRemark<OptimizationRemark>(&F, "OMP170", Remark);
16014d4ea9acSHuber, Joseph 
16029548b74aSJohannes Doerfert       CGUpdater.removeCallSite(*CI);
16039548b74aSJohannes Doerfert       CI->replaceAllUsesWith(ReplVal);
16049548b74aSJohannes Doerfert       CI->eraseFromParent();
16059548b74aSJohannes Doerfert       ++NumOpenMPRuntimeCallsDeduplicated;
16069548b74aSJohannes Doerfert       Changed = true;
16079548b74aSJohannes Doerfert       return true;
16089548b74aSJohannes Doerfert     };
1609624d34afSJohannes Doerfert     RFI.foreachUse(SCC, ReplaceAndDeleteCB);
16109548b74aSJohannes Doerfert 
16119548b74aSJohannes Doerfert     return Changed;
16129548b74aSJohannes Doerfert   }
16139548b74aSJohannes Doerfert 
16149548b74aSJohannes Doerfert   /// Collect arguments that represent the global thread id in \p GTIdArgs.
16159548b74aSJohannes Doerfert   void collectGlobalThreadIdArguments(SmallSetVector<Value *, 16> &GTIdArgs) {
16169548b74aSJohannes Doerfert     // TODO: Below we basically perform a fixpoint iteration with a pessimistic
16179548b74aSJohannes Doerfert     //       initialization. We could define an AbstractAttribute instead and
16189548b74aSJohannes Doerfert     //       run the Attributor here once it can be run as an SCC pass.
16199548b74aSJohannes Doerfert 
16209548b74aSJohannes Doerfert     // Helper to check the argument \p ArgNo at all call sites of \p F for
16219548b74aSJohannes Doerfert     // a GTId.
16229548b74aSJohannes Doerfert     auto CallArgOpIsGTId = [&](Function &F, unsigned ArgNo, CallInst &RefCI) {
16239548b74aSJohannes Doerfert       if (!F.hasLocalLinkage())
16249548b74aSJohannes Doerfert         return false;
16259548b74aSJohannes Doerfert       for (Use &U : F.uses()) {
16269548b74aSJohannes Doerfert         if (CallInst *CI = getCallIfRegularCall(U)) {
16279548b74aSJohannes Doerfert           Value *ArgOp = CI->getArgOperand(ArgNo);
16289548b74aSJohannes Doerfert           if (CI == &RefCI || GTIdArgs.count(ArgOp) ||
16297cfd267cSsstefan1               getCallIfRegularCall(
16307cfd267cSsstefan1                   *ArgOp, &OMPInfoCache.RFIs[OMPRTL___kmpc_global_thread_num]))
16319548b74aSJohannes Doerfert             continue;
16329548b74aSJohannes Doerfert         }
16339548b74aSJohannes Doerfert         return false;
16349548b74aSJohannes Doerfert       }
16359548b74aSJohannes Doerfert       return true;
16369548b74aSJohannes Doerfert     };
16379548b74aSJohannes Doerfert 
16389548b74aSJohannes Doerfert     // Helper to identify uses of a GTId as GTId arguments.
16399548b74aSJohannes Doerfert     auto AddUserArgs = [&](Value &GTId) {
16409548b74aSJohannes Doerfert       for (Use &U : GTId.uses())
16419548b74aSJohannes Doerfert         if (CallInst *CI = dyn_cast<CallInst>(U.getUser()))
16429548b74aSJohannes Doerfert           if (CI->isArgOperand(&U))
16439548b74aSJohannes Doerfert             if (Function *Callee = CI->getCalledFunction())
16449548b74aSJohannes Doerfert               if (CallArgOpIsGTId(*Callee, U.getOperandNo(), *CI))
16459548b74aSJohannes Doerfert                 GTIdArgs.insert(Callee->getArg(U.getOperandNo()));
16469548b74aSJohannes Doerfert     };
16479548b74aSJohannes Doerfert 
16489548b74aSJohannes Doerfert     // The argument users of __kmpc_global_thread_num calls are GTIds.
16497cfd267cSsstefan1     OMPInformationCache::RuntimeFunctionInfo &GlobThreadNumRFI =
16507cfd267cSsstefan1         OMPInfoCache.RFIs[OMPRTL___kmpc_global_thread_num];
16517cfd267cSsstefan1 
1652624d34afSJohannes Doerfert     GlobThreadNumRFI.foreachUse(SCC, [&](Use &U, Function &F) {
16538855fec3SJohannes Doerfert       if (CallInst *CI = getCallIfRegularCall(U, &GlobThreadNumRFI))
16549548b74aSJohannes Doerfert         AddUserArgs(*CI);
16558855fec3SJohannes Doerfert       return false;
16568855fec3SJohannes Doerfert     });
16579548b74aSJohannes Doerfert 
16589548b74aSJohannes Doerfert     // Transitively search for more arguments by looking at the users of the
16599548b74aSJohannes Doerfert     // ones we know already. During the search the GTIdArgs vector is extended
16609548b74aSJohannes Doerfert     // so we cannot cache the size nor can we use a range based for.
16619548b74aSJohannes Doerfert     for (unsigned u = 0; u < GTIdArgs.size(); ++u)
16629548b74aSJohannes Doerfert       AddUserArgs(*GTIdArgs[u]);
16639548b74aSJohannes Doerfert   }
16649548b74aSJohannes Doerfert 
16655b0581aeSJohannes Doerfert   /// Kernel (=GPU) optimizations and utility functions
16665b0581aeSJohannes Doerfert   ///
16675b0581aeSJohannes Doerfert   ///{{
16685b0581aeSJohannes Doerfert 
16695b0581aeSJohannes Doerfert   /// Check if \p F is a kernel, hence entry point for target offloading.
16705b0581aeSJohannes Doerfert   bool isKernel(Function &F) { return OMPInfoCache.Kernels.count(&F); }
16715b0581aeSJohannes Doerfert 
16725b0581aeSJohannes Doerfert   /// Cache to remember the unique kernel for a function.
16735b0581aeSJohannes Doerfert   DenseMap<Function *, Optional<Kernel>> UniqueKernelMap;
16745b0581aeSJohannes Doerfert 
16755b0581aeSJohannes Doerfert   /// Find the unique kernel that will execute \p F, if any.
16765b0581aeSJohannes Doerfert   Kernel getUniqueKernelFor(Function &F);
16775b0581aeSJohannes Doerfert 
16785b0581aeSJohannes Doerfert   /// Find the unique kernel that will execute \p I, if any.
16795b0581aeSJohannes Doerfert   Kernel getUniqueKernelFor(Instruction &I) {
16805b0581aeSJohannes Doerfert     return getUniqueKernelFor(*I.getFunction());
16815b0581aeSJohannes Doerfert   }
16825b0581aeSJohannes Doerfert 
16835b0581aeSJohannes Doerfert   /// Rewrite the device (=GPU) code state machine create in non-SPMD mode in
16845b0581aeSJohannes Doerfert   /// the cases we can avoid taking the address of a function.
16855b0581aeSJohannes Doerfert   bool rewriteDeviceCodeStateMachine();
16865b0581aeSJohannes Doerfert 
16875b0581aeSJohannes Doerfert   ///
16885b0581aeSJohannes Doerfert   ///}}
16895b0581aeSJohannes Doerfert 
16904d4ea9acSHuber, Joseph   /// Emit a remark generically
16914d4ea9acSHuber, Joseph   ///
16924d4ea9acSHuber, Joseph   /// This template function can be used to generically emit a remark. The
16934d4ea9acSHuber, Joseph   /// RemarkKind should be one of the following:
16944d4ea9acSHuber, Joseph   ///   - OptimizationRemark to indicate a successful optimization attempt
16954d4ea9acSHuber, Joseph   ///   - OptimizationRemarkMissed to report a failed optimization attempt
16964d4ea9acSHuber, Joseph   ///   - OptimizationRemarkAnalysis to provide additional information about an
16974d4ea9acSHuber, Joseph   ///     optimization attempt
16984d4ea9acSHuber, Joseph   ///
16994d4ea9acSHuber, Joseph   /// The remark is built using a callback function provided by the caller that
17004d4ea9acSHuber, Joseph   /// takes a RemarkKind as input and returns a RemarkKind.
17012db182ffSJoseph Huber   template <typename RemarkKind, typename RemarkCallBack>
17022db182ffSJoseph Huber   void emitRemark(Instruction *I, StringRef RemarkName,
1703e8039ad4SJohannes Doerfert                   RemarkCallBack &&RemarkCB) const {
17042db182ffSJoseph Huber     Function *F = I->getParent()->getParent();
17054d4ea9acSHuber, Joseph     auto &ORE = OREGetter(F);
17064d4ea9acSHuber, Joseph 
17072c31d5ebSJoseph Huber     if (RemarkName.startswith("OMP"))
17082c31d5ebSJoseph Huber       ORE.emit([&]() {
17092c31d5ebSJoseph Huber         return RemarkCB(RemarkKind(DEBUG_TYPE, RemarkName, I))
17102c31d5ebSJoseph Huber                << " [" << RemarkName << "]";
17112c31d5ebSJoseph Huber       });
17122c31d5ebSJoseph Huber     else
17132c31d5ebSJoseph Huber       ORE.emit(
17142c31d5ebSJoseph Huber           [&]() { return RemarkCB(RemarkKind(DEBUG_TYPE, RemarkName, I)); });
17154d4ea9acSHuber, Joseph   }
17164d4ea9acSHuber, Joseph 
17172db182ffSJoseph Huber   /// Emit a remark on a function.
17182db182ffSJoseph Huber   template <typename RemarkKind, typename RemarkCallBack>
17192db182ffSJoseph Huber   void emitRemark(Function *F, StringRef RemarkName,
17202db182ffSJoseph Huber                   RemarkCallBack &&RemarkCB) const {
17210f426935Ssstefan1     auto &ORE = OREGetter(F);
17220f426935Ssstefan1 
17232c31d5ebSJoseph Huber     if (RemarkName.startswith("OMP"))
17242c31d5ebSJoseph Huber       ORE.emit([&]() {
17252c31d5ebSJoseph Huber         return RemarkCB(RemarkKind(DEBUG_TYPE, RemarkName, F))
17262c31d5ebSJoseph Huber                << " [" << RemarkName << "]";
17272c31d5ebSJoseph Huber       });
17282c31d5ebSJoseph Huber     else
17292c31d5ebSJoseph Huber       ORE.emit(
17302c31d5ebSJoseph Huber           [&]() { return RemarkCB(RemarkKind(DEBUG_TYPE, RemarkName, F)); });
17310f426935Ssstefan1   }
17320f426935Ssstefan1 
1733b726c557SJohannes Doerfert   /// The underlying module.
17349548b74aSJohannes Doerfert   Module &M;
17359548b74aSJohannes Doerfert 
17369548b74aSJohannes Doerfert   /// The SCC we are operating on.
1737ee17263aSJohannes Doerfert   SmallVectorImpl<Function *> &SCC;
17389548b74aSJohannes Doerfert 
17399548b74aSJohannes Doerfert   /// Callback to update the call graph, the first argument is a removed call,
17409548b74aSJohannes Doerfert   /// the second an optional replacement call.
17419548b74aSJohannes Doerfert   CallGraphUpdater &CGUpdater;
17429548b74aSJohannes Doerfert 
17434d4ea9acSHuber, Joseph   /// Callback to get an OptimizationRemarkEmitter from a Function *
17444d4ea9acSHuber, Joseph   OptimizationRemarkGetter OREGetter;
17454d4ea9acSHuber, Joseph 
17467cfd267cSsstefan1   /// OpenMP-specific information cache. Also Used for Attributor runs.
17477cfd267cSsstefan1   OMPInformationCache &OMPInfoCache;
1748b8235d2bSsstefan1 
1749b8235d2bSsstefan1   /// Attributor instance.
1750b8235d2bSsstefan1   Attributor &A;
1751b8235d2bSsstefan1 
1752b8235d2bSsstefan1   /// Helper function to run Attributor on SCC.
1753d9659bf6SJohannes Doerfert   bool runAttributor(bool IsModulePass) {
1754b8235d2bSsstefan1     if (SCC.empty())
1755b8235d2bSsstefan1       return false;
1756b8235d2bSsstefan1 
1757d9659bf6SJohannes Doerfert     registerAAs(IsModulePass);
1758b8235d2bSsstefan1 
1759b8235d2bSsstefan1     ChangeStatus Changed = A.run();
1760b8235d2bSsstefan1 
1761b8235d2bSsstefan1     LLVM_DEBUG(dbgs() << "[Attributor] Done with " << SCC.size()
1762b8235d2bSsstefan1                       << " functions, result: " << Changed << ".\n");
1763b8235d2bSsstefan1 
1764b8235d2bSsstefan1     return Changed == ChangeStatus::CHANGED;
1765b8235d2bSsstefan1   }
1766b8235d2bSsstefan1 
1767b8235d2bSsstefan1   /// Populate the Attributor with abstract attribute opportunities in the
1768b8235d2bSsstefan1   /// function.
1769d9659bf6SJohannes Doerfert   void registerAAs(bool IsModulePass);
1770b8235d2bSsstefan1 };
1771b8235d2bSsstefan1 
17725b0581aeSJohannes Doerfert Kernel OpenMPOpt::getUniqueKernelFor(Function &F) {
17735b0581aeSJohannes Doerfert   if (!OMPInfoCache.ModuleSlice.count(&F))
17745b0581aeSJohannes Doerfert     return nullptr;
17755b0581aeSJohannes Doerfert 
17765b0581aeSJohannes Doerfert   // Use a scope to keep the lifetime of the CachedKernel short.
17775b0581aeSJohannes Doerfert   {
17785b0581aeSJohannes Doerfert     Optional<Kernel> &CachedKernel = UniqueKernelMap[&F];
17795b0581aeSJohannes Doerfert     if (CachedKernel)
17805b0581aeSJohannes Doerfert       return *CachedKernel;
17815b0581aeSJohannes Doerfert 
17825b0581aeSJohannes Doerfert     // TODO: We should use an AA to create an (optimistic and callback
17835b0581aeSJohannes Doerfert     //       call-aware) call graph. For now we stick to simple patterns that
17845b0581aeSJohannes Doerfert     //       are less powerful, basically the worst fixpoint.
17855b0581aeSJohannes Doerfert     if (isKernel(F)) {
17865b0581aeSJohannes Doerfert       CachedKernel = Kernel(&F);
17875b0581aeSJohannes Doerfert       return *CachedKernel;
17885b0581aeSJohannes Doerfert     }
17895b0581aeSJohannes Doerfert 
17905b0581aeSJohannes Doerfert     CachedKernel = nullptr;
1791994bb6ebSJohannes Doerfert     if (!F.hasLocalLinkage()) {
1792994bb6ebSJohannes Doerfert 
1793994bb6ebSJohannes Doerfert       // See https://openmp.llvm.org/remarks/OptimizationRemarks.html
17942db182ffSJoseph Huber       auto Remark = [&](OptimizationRemarkAnalysis ORA) {
1795eef6601bSJoseph Huber         return ORA << "Potentially unknown OpenMP target region caller.";
1796994bb6ebSJohannes Doerfert       };
17972db182ffSJoseph Huber       emitRemark<OptimizationRemarkAnalysis>(&F, "OMP100", Remark);
1798994bb6ebSJohannes Doerfert 
17995b0581aeSJohannes Doerfert       return nullptr;
18005b0581aeSJohannes Doerfert     }
1801994bb6ebSJohannes Doerfert   }
18025b0581aeSJohannes Doerfert 
18035b0581aeSJohannes Doerfert   auto GetUniqueKernelForUse = [&](const Use &U) -> Kernel {
18045b0581aeSJohannes Doerfert     if (auto *Cmp = dyn_cast<ICmpInst>(U.getUser())) {
18055b0581aeSJohannes Doerfert       // Allow use in equality comparisons.
18065b0581aeSJohannes Doerfert       if (Cmp->isEquality())
18075b0581aeSJohannes Doerfert         return getUniqueKernelFor(*Cmp);
18085b0581aeSJohannes Doerfert       return nullptr;
18095b0581aeSJohannes Doerfert     }
18105b0581aeSJohannes Doerfert     if (auto *CB = dyn_cast<CallBase>(U.getUser())) {
18115b0581aeSJohannes Doerfert       // Allow direct calls.
18125b0581aeSJohannes Doerfert       if (CB->isCallee(&U))
18135b0581aeSJohannes Doerfert         return getUniqueKernelFor(*CB);
1814a2dbfb6bSGiorgis Georgakoudis 
1815a2dbfb6bSGiorgis Georgakoudis       OMPInformationCache::RuntimeFunctionInfo &KernelParallelRFI =
1816a2dbfb6bSGiorgis Georgakoudis           OMPInfoCache.RFIs[OMPRTL___kmpc_parallel_51];
1817a2dbfb6bSGiorgis Georgakoudis       // Allow the use in __kmpc_parallel_51 calls.
1818a2dbfb6bSGiorgis Georgakoudis       if (OpenMPOpt::getCallIfRegularCall(*U.getUser(), &KernelParallelRFI))
18195b0581aeSJohannes Doerfert         return getUniqueKernelFor(*CB);
18205b0581aeSJohannes Doerfert       return nullptr;
18215b0581aeSJohannes Doerfert     }
18225b0581aeSJohannes Doerfert     // Disallow every other use.
18235b0581aeSJohannes Doerfert     return nullptr;
18245b0581aeSJohannes Doerfert   };
18255b0581aeSJohannes Doerfert 
18265b0581aeSJohannes Doerfert   // TODO: In the future we want to track more than just a unique kernel.
18275b0581aeSJohannes Doerfert   SmallPtrSet<Kernel, 2> PotentialKernels;
18288d8ce85bSsstefan1   OMPInformationCache::foreachUse(F, [&](const Use &U) {
18295b0581aeSJohannes Doerfert     PotentialKernels.insert(GetUniqueKernelForUse(U));
18305b0581aeSJohannes Doerfert   });
18315b0581aeSJohannes Doerfert 
18325b0581aeSJohannes Doerfert   Kernel K = nullptr;
18335b0581aeSJohannes Doerfert   if (PotentialKernels.size() == 1)
18345b0581aeSJohannes Doerfert     K = *PotentialKernels.begin();
18355b0581aeSJohannes Doerfert 
18365b0581aeSJohannes Doerfert   // Cache the result.
18375b0581aeSJohannes Doerfert   UniqueKernelMap[&F] = K;
18385b0581aeSJohannes Doerfert 
18395b0581aeSJohannes Doerfert   return K;
18405b0581aeSJohannes Doerfert }
18415b0581aeSJohannes Doerfert 
18425b0581aeSJohannes Doerfert bool OpenMPOpt::rewriteDeviceCodeStateMachine() {
1843a2dbfb6bSGiorgis Georgakoudis   OMPInformationCache::RuntimeFunctionInfo &KernelParallelRFI =
1844a2dbfb6bSGiorgis Georgakoudis       OMPInfoCache.RFIs[OMPRTL___kmpc_parallel_51];
18455b0581aeSJohannes Doerfert 
18465b0581aeSJohannes Doerfert   bool Changed = false;
1847a2dbfb6bSGiorgis Georgakoudis   if (!KernelParallelRFI)
18485b0581aeSJohannes Doerfert     return Changed;
18495b0581aeSJohannes Doerfert 
18505b0581aeSJohannes Doerfert   for (Function *F : SCC) {
18515b0581aeSJohannes Doerfert 
1852a2dbfb6bSGiorgis Georgakoudis     // Check if the function is a use in a __kmpc_parallel_51 call at
18535b0581aeSJohannes Doerfert     // all.
18545b0581aeSJohannes Doerfert     bool UnknownUse = false;
1855a2dbfb6bSGiorgis Georgakoudis     bool KernelParallelUse = false;
18565b0581aeSJohannes Doerfert     unsigned NumDirectCalls = 0;
18575b0581aeSJohannes Doerfert 
18585b0581aeSJohannes Doerfert     SmallVector<Use *, 2> ToBeReplacedStateMachineUses;
18598d8ce85bSsstefan1     OMPInformationCache::foreachUse(*F, [&](Use &U) {
18605b0581aeSJohannes Doerfert       if (auto *CB = dyn_cast<CallBase>(U.getUser()))
18615b0581aeSJohannes Doerfert         if (CB->isCallee(&U)) {
18625b0581aeSJohannes Doerfert           ++NumDirectCalls;
18635b0581aeSJohannes Doerfert           return;
18645b0581aeSJohannes Doerfert         }
18655b0581aeSJohannes Doerfert 
186681db6144SMichael Liao       if (isa<ICmpInst>(U.getUser())) {
18675b0581aeSJohannes Doerfert         ToBeReplacedStateMachineUses.push_back(&U);
18685b0581aeSJohannes Doerfert         return;
18695b0581aeSJohannes Doerfert       }
1870a2dbfb6bSGiorgis Georgakoudis 
1871a2dbfb6bSGiorgis Georgakoudis       // Find wrapper functions that represent parallel kernels.
1872a2dbfb6bSGiorgis Georgakoudis       CallInst *CI =
1873a2dbfb6bSGiorgis Georgakoudis           OpenMPOpt::getCallIfRegularCall(*U.getUser(), &KernelParallelRFI);
1874a2dbfb6bSGiorgis Georgakoudis       const unsigned int WrapperFunctionArgNo = 6;
1875a2dbfb6bSGiorgis Georgakoudis       if (!KernelParallelUse && CI &&
1876a2dbfb6bSGiorgis Georgakoudis           CI->getArgOperandNo(&U) == WrapperFunctionArgNo) {
1877a2dbfb6bSGiorgis Georgakoudis         KernelParallelUse = true;
18785b0581aeSJohannes Doerfert         ToBeReplacedStateMachineUses.push_back(&U);
18795b0581aeSJohannes Doerfert         return;
18805b0581aeSJohannes Doerfert       }
18815b0581aeSJohannes Doerfert       UnknownUse = true;
18825b0581aeSJohannes Doerfert     });
18835b0581aeSJohannes Doerfert 
1884a2dbfb6bSGiorgis Georgakoudis     // Do not emit a remark if we haven't seen a __kmpc_parallel_51
1885fec1f210SJohannes Doerfert     // use.
1886a2dbfb6bSGiorgis Georgakoudis     if (!KernelParallelUse)
18875b0581aeSJohannes Doerfert       continue;
18885b0581aeSJohannes Doerfert 
1889fec1f210SJohannes Doerfert     // If this ever hits, we should investigate.
1890fec1f210SJohannes Doerfert     // TODO: Checking the number of uses is not a necessary restriction and
1891fec1f210SJohannes Doerfert     // should be lifted.
1892fec1f210SJohannes Doerfert     if (UnknownUse || NumDirectCalls != 1 ||
1893d9659bf6SJohannes Doerfert         ToBeReplacedStateMachineUses.size() > 2) {
18942db182ffSJoseph Huber       auto Remark = [&](OptimizationRemarkAnalysis ORA) {
18952db182ffSJoseph Huber         return ORA << "Parallel region is used in "
1896fec1f210SJohannes Doerfert                    << (UnknownUse ? "unknown" : "unexpected")
1897eef6601bSJoseph Huber                    << " ways. Will not attempt to rewrite the state machine.";
1898fec1f210SJohannes Doerfert       };
18992c31d5ebSJoseph Huber       emitRemark<OptimizationRemarkAnalysis>(F, "OMP101", Remark);
19005b0581aeSJohannes Doerfert       continue;
1901fec1f210SJohannes Doerfert     }
19025b0581aeSJohannes Doerfert 
1903a2dbfb6bSGiorgis Georgakoudis     // Even if we have __kmpc_parallel_51 calls, we (for now) give
19045b0581aeSJohannes Doerfert     // up if the function is not called from a unique kernel.
19055b0581aeSJohannes Doerfert     Kernel K = getUniqueKernelFor(*F);
1906fec1f210SJohannes Doerfert     if (!K) {
19072db182ffSJoseph Huber       auto Remark = [&](OptimizationRemarkAnalysis ORA) {
1908eef6601bSJoseph Huber         return ORA << "Parallel region is not called from a unique kernel. "
1909eef6601bSJoseph Huber                       "Will not attempt to rewrite the state machine.";
1910fec1f210SJohannes Doerfert       };
19112c31d5ebSJoseph Huber       emitRemark<OptimizationRemarkAnalysis>(F, "OMP102", Remark);
19125b0581aeSJohannes Doerfert       continue;
1913fec1f210SJohannes Doerfert     }
19145b0581aeSJohannes Doerfert 
19155b0581aeSJohannes Doerfert     // We now know F is a parallel body function called only from the kernel K.
19165b0581aeSJohannes Doerfert     // We also identified the state machine uses in which we replace the
19175b0581aeSJohannes Doerfert     // function pointer by a new global symbol for identification purposes. This
19185b0581aeSJohannes Doerfert     // ensures only direct calls to the function are left.
19195b0581aeSJohannes Doerfert 
19205b0581aeSJohannes Doerfert     Module &M = *F->getParent();
19215b0581aeSJohannes Doerfert     Type *Int8Ty = Type::getInt8Ty(M.getContext());
19225b0581aeSJohannes Doerfert 
19235b0581aeSJohannes Doerfert     auto *ID = new GlobalVariable(
19245b0581aeSJohannes Doerfert         M, Int8Ty, /* isConstant */ true, GlobalValue::PrivateLinkage,
19255b0581aeSJohannes Doerfert         UndefValue::get(Int8Ty), F->getName() + ".ID");
19265b0581aeSJohannes Doerfert 
19275b0581aeSJohannes Doerfert     for (Use *U : ToBeReplacedStateMachineUses)
19285b0581aeSJohannes Doerfert       U->set(ConstantExpr::getBitCast(ID, U->get()->getType()));
19295b0581aeSJohannes Doerfert 
19305b0581aeSJohannes Doerfert     ++NumOpenMPParallelRegionsReplacedInGPUStateMachine;
19315b0581aeSJohannes Doerfert 
19325b0581aeSJohannes Doerfert     Changed = true;
19335b0581aeSJohannes Doerfert   }
19345b0581aeSJohannes Doerfert 
19355b0581aeSJohannes Doerfert   return Changed;
19365b0581aeSJohannes Doerfert }
19375b0581aeSJohannes Doerfert 
1938b8235d2bSsstefan1 /// Abstract Attribute for tracking ICV values.
1939b8235d2bSsstefan1 struct AAICVTracker : public StateWrapper<BooleanState, AbstractAttribute> {
1940b8235d2bSsstefan1   using Base = StateWrapper<BooleanState, AbstractAttribute>;
1941b8235d2bSsstefan1   AAICVTracker(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
1942b8235d2bSsstefan1 
19435dfd7cc4Ssstefan1   void initialize(Attributor &A) override {
19445dfd7cc4Ssstefan1     Function *F = getAnchorScope();
19455dfd7cc4Ssstefan1     if (!F || !A.isFunctionIPOAmendable(*F))
19465dfd7cc4Ssstefan1       indicatePessimisticFixpoint();
19475dfd7cc4Ssstefan1   }
19485dfd7cc4Ssstefan1 
1949b8235d2bSsstefan1   /// Returns true if value is assumed to be tracked.
1950b8235d2bSsstefan1   bool isAssumedTracked() const { return getAssumed(); }
1951b8235d2bSsstefan1 
1952b8235d2bSsstefan1   /// Returns true if value is known to be tracked.
1953b8235d2bSsstefan1   bool isKnownTracked() const { return getAssumed(); }
1954b8235d2bSsstefan1 
1955b8235d2bSsstefan1   /// Create an abstract attribute biew for the position \p IRP.
1956b8235d2bSsstefan1   static AAICVTracker &createForPosition(const IRPosition &IRP, Attributor &A);
1957b8235d2bSsstefan1 
1958b8235d2bSsstefan1   /// Return the value with which \p I can be replaced for specific \p ICV.
19595dfd7cc4Ssstefan1   virtual Optional<Value *> getReplacementValue(InternalControlVar ICV,
19605dfd7cc4Ssstefan1                                                 const Instruction *I,
19615dfd7cc4Ssstefan1                                                 Attributor &A) const {
19625dfd7cc4Ssstefan1     return None;
19635dfd7cc4Ssstefan1   }
19645dfd7cc4Ssstefan1 
19655dfd7cc4Ssstefan1   /// Return an assumed unique ICV value if a single candidate is found. If
19665dfd7cc4Ssstefan1   /// there cannot be one, return a nullptr. If it is not clear yet, return the
19675dfd7cc4Ssstefan1   /// Optional::NoneType.
19685dfd7cc4Ssstefan1   virtual Optional<Value *>
19695dfd7cc4Ssstefan1   getUniqueReplacementValue(InternalControlVar ICV) const = 0;
19705dfd7cc4Ssstefan1 
19715dfd7cc4Ssstefan1   // Currently only nthreads is being tracked.
19725dfd7cc4Ssstefan1   // this array will only grow with time.
19735dfd7cc4Ssstefan1   InternalControlVar TrackableICVs[1] = {ICV_nthreads};
1974b8235d2bSsstefan1 
1975b8235d2bSsstefan1   /// See AbstractAttribute::getName()
1976b8235d2bSsstefan1   const std::string getName() const override { return "AAICVTracker"; }
1977b8235d2bSsstefan1 
1978233af895SLuofan Chen   /// See AbstractAttribute::getIdAddr()
1979233af895SLuofan Chen   const char *getIdAddr() const override { return &ID; }
1980233af895SLuofan Chen 
1981233af895SLuofan Chen   /// This function should return true if the type of the \p AA is AAICVTracker
1982233af895SLuofan Chen   static bool classof(const AbstractAttribute *AA) {
1983233af895SLuofan Chen     return (AA->getIdAddr() == &ID);
1984233af895SLuofan Chen   }
1985233af895SLuofan Chen 
1986b8235d2bSsstefan1   static const char ID;
1987b8235d2bSsstefan1 };
1988b8235d2bSsstefan1 
1989b8235d2bSsstefan1 struct AAICVTrackerFunction : public AAICVTracker {
1990b8235d2bSsstefan1   AAICVTrackerFunction(const IRPosition &IRP, Attributor &A)
1991b8235d2bSsstefan1       : AAICVTracker(IRP, A) {}
1992b8235d2bSsstefan1 
1993b8235d2bSsstefan1   // FIXME: come up with better string.
19945dfd7cc4Ssstefan1   const std::string getAsStr() const override { return "ICVTrackerFunction"; }
1995b8235d2bSsstefan1 
1996b8235d2bSsstefan1   // FIXME: come up with some stats.
1997b8235d2bSsstefan1   void trackStatistics() const override {}
1998b8235d2bSsstefan1 
19995dfd7cc4Ssstefan1   /// We don't manifest anything for this AA.
2000b8235d2bSsstefan1   ChangeStatus manifest(Attributor &A) override {
20015dfd7cc4Ssstefan1     return ChangeStatus::UNCHANGED;
2002b8235d2bSsstefan1   }
2003b8235d2bSsstefan1 
2004b8235d2bSsstefan1   // Map of ICV to their values at specific program point.
20055dfd7cc4Ssstefan1   EnumeratedArray<DenseMap<Instruction *, Value *>, InternalControlVar,
2006b8235d2bSsstefan1                   InternalControlVar::ICV___last>
20075dfd7cc4Ssstefan1       ICVReplacementValuesMap;
2008b8235d2bSsstefan1 
2009b8235d2bSsstefan1   ChangeStatus updateImpl(Attributor &A) override {
2010b8235d2bSsstefan1     ChangeStatus HasChanged = ChangeStatus::UNCHANGED;
2011b8235d2bSsstefan1 
2012b8235d2bSsstefan1     Function *F = getAnchorScope();
2013b8235d2bSsstefan1 
2014b8235d2bSsstefan1     auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
2015b8235d2bSsstefan1 
2016b8235d2bSsstefan1     for (InternalControlVar ICV : TrackableICVs) {
2017b8235d2bSsstefan1       auto &SetterRFI = OMPInfoCache.RFIs[OMPInfoCache.ICVs[ICV].Setter];
2018b8235d2bSsstefan1 
20195dfd7cc4Ssstefan1       auto &ValuesMap = ICVReplacementValuesMap[ICV];
2020b8235d2bSsstefan1       auto TrackValues = [&](Use &U, Function &) {
2021b8235d2bSsstefan1         CallInst *CI = OpenMPOpt::getCallIfRegularCall(U);
2022b8235d2bSsstefan1         if (!CI)
2023b8235d2bSsstefan1           return false;
2024b8235d2bSsstefan1 
2025b8235d2bSsstefan1         // FIXME: handle setters with more that 1 arguments.
2026b8235d2bSsstefan1         /// Track new value.
20275dfd7cc4Ssstefan1         if (ValuesMap.insert(std::make_pair(CI, CI->getArgOperand(0))).second)
2028b8235d2bSsstefan1           HasChanged = ChangeStatus::CHANGED;
2029b8235d2bSsstefan1 
2030b8235d2bSsstefan1         return false;
2031b8235d2bSsstefan1       };
2032b8235d2bSsstefan1 
20335dfd7cc4Ssstefan1       auto CallCheck = [&](Instruction &I) {
20345dfd7cc4Ssstefan1         Optional<Value *> ReplVal = getValueForCall(A, &I, ICV);
20355dfd7cc4Ssstefan1         if (ReplVal.hasValue() &&
20365dfd7cc4Ssstefan1             ValuesMap.insert(std::make_pair(&I, *ReplVal)).second)
20375dfd7cc4Ssstefan1           HasChanged = ChangeStatus::CHANGED;
20385dfd7cc4Ssstefan1 
20395dfd7cc4Ssstefan1         return true;
20405dfd7cc4Ssstefan1       };
20415dfd7cc4Ssstefan1 
20425dfd7cc4Ssstefan1       // Track all changes of an ICV.
2043b8235d2bSsstefan1       SetterRFI.foreachUse(TrackValues, F);
20445dfd7cc4Ssstefan1 
2045792aac98SJohannes Doerfert       bool UsedAssumedInformation = false;
20465dfd7cc4Ssstefan1       A.checkForAllInstructions(CallCheck, *this, {Instruction::Call},
2047792aac98SJohannes Doerfert                                 UsedAssumedInformation,
20485dfd7cc4Ssstefan1                                 /* CheckBBLivenessOnly */ true);
20495dfd7cc4Ssstefan1 
20505dfd7cc4Ssstefan1       /// TODO: Figure out a way to avoid adding entry in
20515dfd7cc4Ssstefan1       /// ICVReplacementValuesMap
20525dfd7cc4Ssstefan1       Instruction *Entry = &F->getEntryBlock().front();
20535dfd7cc4Ssstefan1       if (HasChanged == ChangeStatus::CHANGED && !ValuesMap.count(Entry))
20545dfd7cc4Ssstefan1         ValuesMap.insert(std::make_pair(Entry, nullptr));
2055b8235d2bSsstefan1     }
2056b8235d2bSsstefan1 
2057b8235d2bSsstefan1     return HasChanged;
2058b8235d2bSsstefan1   }
2059b8235d2bSsstefan1 
20605dfd7cc4Ssstefan1   /// Hepler to check if \p I is a call and get the value for it if it is
20615dfd7cc4Ssstefan1   /// unique.
20625dfd7cc4Ssstefan1   Optional<Value *> getValueForCall(Attributor &A, const Instruction *I,
20635dfd7cc4Ssstefan1                                     InternalControlVar &ICV) const {
2064b8235d2bSsstefan1 
20655dfd7cc4Ssstefan1     const auto *CB = dyn_cast<CallBase>(I);
2066dcaec812SJohannes Doerfert     if (!CB || CB->hasFnAttr("no_openmp") ||
2067dcaec812SJohannes Doerfert         CB->hasFnAttr("no_openmp_routines"))
20685dfd7cc4Ssstefan1       return None;
20695dfd7cc4Ssstefan1 
2070b8235d2bSsstefan1     auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
2071b8235d2bSsstefan1     auto &GetterRFI = OMPInfoCache.RFIs[OMPInfoCache.ICVs[ICV].Getter];
20725dfd7cc4Ssstefan1     auto &SetterRFI = OMPInfoCache.RFIs[OMPInfoCache.ICVs[ICV].Setter];
20735dfd7cc4Ssstefan1     Function *CalledFunction = CB->getCalledFunction();
2074b8235d2bSsstefan1 
20754eef14f9SWei Wang     // Indirect call, assume ICV changes.
20764eef14f9SWei Wang     if (CalledFunction == nullptr)
20774eef14f9SWei Wang       return nullptr;
20785dfd7cc4Ssstefan1     if (CalledFunction == GetterRFI.Declaration)
20795dfd7cc4Ssstefan1       return None;
20805dfd7cc4Ssstefan1     if (CalledFunction == SetterRFI.Declaration) {
20815dfd7cc4Ssstefan1       if (ICVReplacementValuesMap[ICV].count(I))
20825dfd7cc4Ssstefan1         return ICVReplacementValuesMap[ICV].lookup(I);
20835dfd7cc4Ssstefan1 
20845dfd7cc4Ssstefan1       return nullptr;
20855dfd7cc4Ssstefan1     }
20865dfd7cc4Ssstefan1 
20875dfd7cc4Ssstefan1     // Since we don't know, assume it changes the ICV.
20885dfd7cc4Ssstefan1     if (CalledFunction->isDeclaration())
20895dfd7cc4Ssstefan1       return nullptr;
20905dfd7cc4Ssstefan1 
20915b70c12fSJohannes Doerfert     const auto &ICVTrackingAA = A.getAAFor<AAICVTracker>(
20925b70c12fSJohannes Doerfert         *this, IRPosition::callsite_returned(*CB), DepClassTy::REQUIRED);
20935dfd7cc4Ssstefan1 
20945dfd7cc4Ssstefan1     if (ICVTrackingAA.isAssumedTracked())
20955dfd7cc4Ssstefan1       return ICVTrackingAA.getUniqueReplacementValue(ICV);
20965dfd7cc4Ssstefan1 
20975dfd7cc4Ssstefan1     // If we don't know, assume it changes.
20985dfd7cc4Ssstefan1     return nullptr;
20995dfd7cc4Ssstefan1   }
21005dfd7cc4Ssstefan1 
21015dfd7cc4Ssstefan1   // We don't check unique value for a function, so return None.
21025dfd7cc4Ssstefan1   Optional<Value *>
21035dfd7cc4Ssstefan1   getUniqueReplacementValue(InternalControlVar ICV) const override {
21045dfd7cc4Ssstefan1     return None;
21055dfd7cc4Ssstefan1   }
21065dfd7cc4Ssstefan1 
21075dfd7cc4Ssstefan1   /// Return the value with which \p I can be replaced for specific \p ICV.
21085dfd7cc4Ssstefan1   Optional<Value *> getReplacementValue(InternalControlVar ICV,
21095dfd7cc4Ssstefan1                                         const Instruction *I,
21105dfd7cc4Ssstefan1                                         Attributor &A) const override {
21115dfd7cc4Ssstefan1     const auto &ValuesMap = ICVReplacementValuesMap[ICV];
21125dfd7cc4Ssstefan1     if (ValuesMap.count(I))
21135dfd7cc4Ssstefan1       return ValuesMap.lookup(I);
21145dfd7cc4Ssstefan1 
21155dfd7cc4Ssstefan1     SmallVector<const Instruction *, 16> Worklist;
21165dfd7cc4Ssstefan1     SmallPtrSet<const Instruction *, 16> Visited;
21175dfd7cc4Ssstefan1     Worklist.push_back(I);
21185dfd7cc4Ssstefan1 
21195dfd7cc4Ssstefan1     Optional<Value *> ReplVal;
21205dfd7cc4Ssstefan1 
21215dfd7cc4Ssstefan1     while (!Worklist.empty()) {
21225dfd7cc4Ssstefan1       const Instruction *CurrInst = Worklist.pop_back_val();
21235dfd7cc4Ssstefan1       if (!Visited.insert(CurrInst).second)
2124b8235d2bSsstefan1         continue;
2125b8235d2bSsstefan1 
21265dfd7cc4Ssstefan1       const BasicBlock *CurrBB = CurrInst->getParent();
21275dfd7cc4Ssstefan1 
21285dfd7cc4Ssstefan1       // Go up and look for all potential setters/calls that might change the
21295dfd7cc4Ssstefan1       // ICV.
21305dfd7cc4Ssstefan1       while ((CurrInst = CurrInst->getPrevNode())) {
21315dfd7cc4Ssstefan1         if (ValuesMap.count(CurrInst)) {
21325dfd7cc4Ssstefan1           Optional<Value *> NewReplVal = ValuesMap.lookup(CurrInst);
21335dfd7cc4Ssstefan1           // Unknown value, track new.
21345dfd7cc4Ssstefan1           if (!ReplVal.hasValue()) {
21355dfd7cc4Ssstefan1             ReplVal = NewReplVal;
21365dfd7cc4Ssstefan1             break;
21375dfd7cc4Ssstefan1           }
21385dfd7cc4Ssstefan1 
21395dfd7cc4Ssstefan1           // If we found a new value, we can't know the icv value anymore.
21405dfd7cc4Ssstefan1           if (NewReplVal.hasValue())
21415dfd7cc4Ssstefan1             if (ReplVal != NewReplVal)
2142b8235d2bSsstefan1               return nullptr;
2143b8235d2bSsstefan1 
21445dfd7cc4Ssstefan1           break;
2145b8235d2bSsstefan1         }
2146b8235d2bSsstefan1 
21475dfd7cc4Ssstefan1         Optional<Value *> NewReplVal = getValueForCall(A, CurrInst, ICV);
21485dfd7cc4Ssstefan1         if (!NewReplVal.hasValue())
21495dfd7cc4Ssstefan1           continue;
21505dfd7cc4Ssstefan1 
21515dfd7cc4Ssstefan1         // Unknown value, track new.
21525dfd7cc4Ssstefan1         if (!ReplVal.hasValue()) {
21535dfd7cc4Ssstefan1           ReplVal = NewReplVal;
21545dfd7cc4Ssstefan1           break;
2155b8235d2bSsstefan1         }
2156b8235d2bSsstefan1 
21575dfd7cc4Ssstefan1         // if (NewReplVal.hasValue())
21585dfd7cc4Ssstefan1         // We found a new value, we can't know the icv value anymore.
21595dfd7cc4Ssstefan1         if (ReplVal != NewReplVal)
2160b8235d2bSsstefan1           return nullptr;
2161b8235d2bSsstefan1       }
21625dfd7cc4Ssstefan1 
21635dfd7cc4Ssstefan1       // If we are in the same BB and we have a value, we are done.
21645dfd7cc4Ssstefan1       if (CurrBB == I->getParent() && ReplVal.hasValue())
21655dfd7cc4Ssstefan1         return ReplVal;
21665dfd7cc4Ssstefan1 
21675dfd7cc4Ssstefan1       // Go through all predecessors and add terminators for analysis.
21685dfd7cc4Ssstefan1       for (const BasicBlock *Pred : predecessors(CurrBB))
21695dfd7cc4Ssstefan1         if (const Instruction *Terminator = Pred->getTerminator())
21705dfd7cc4Ssstefan1           Worklist.push_back(Terminator);
21715dfd7cc4Ssstefan1     }
21725dfd7cc4Ssstefan1 
21735dfd7cc4Ssstefan1     return ReplVal;
21745dfd7cc4Ssstefan1   }
21755dfd7cc4Ssstefan1 };
21765dfd7cc4Ssstefan1 
21775dfd7cc4Ssstefan1 struct AAICVTrackerFunctionReturned : AAICVTracker {
21785dfd7cc4Ssstefan1   AAICVTrackerFunctionReturned(const IRPosition &IRP, Attributor &A)
21795dfd7cc4Ssstefan1       : AAICVTracker(IRP, A) {}
21805dfd7cc4Ssstefan1 
21815dfd7cc4Ssstefan1   // FIXME: come up with better string.
21825dfd7cc4Ssstefan1   const std::string getAsStr() const override {
21835dfd7cc4Ssstefan1     return "ICVTrackerFunctionReturned";
21845dfd7cc4Ssstefan1   }
21855dfd7cc4Ssstefan1 
21865dfd7cc4Ssstefan1   // FIXME: come up with some stats.
21875dfd7cc4Ssstefan1   void trackStatistics() const override {}
21885dfd7cc4Ssstefan1 
21895dfd7cc4Ssstefan1   /// We don't manifest anything for this AA.
21905dfd7cc4Ssstefan1   ChangeStatus manifest(Attributor &A) override {
21915dfd7cc4Ssstefan1     return ChangeStatus::UNCHANGED;
21925dfd7cc4Ssstefan1   }
21935dfd7cc4Ssstefan1 
21945dfd7cc4Ssstefan1   // Map of ICV to their values at specific program point.
21955dfd7cc4Ssstefan1   EnumeratedArray<Optional<Value *>, InternalControlVar,
21965dfd7cc4Ssstefan1                   InternalControlVar::ICV___last>
21975dfd7cc4Ssstefan1       ICVReplacementValuesMap;
21985dfd7cc4Ssstefan1 
21995dfd7cc4Ssstefan1   /// Return the value with which \p I can be replaced for specific \p ICV.
22005dfd7cc4Ssstefan1   Optional<Value *>
22015dfd7cc4Ssstefan1   getUniqueReplacementValue(InternalControlVar ICV) const override {
22025dfd7cc4Ssstefan1     return ICVReplacementValuesMap[ICV];
22035dfd7cc4Ssstefan1   }
22045dfd7cc4Ssstefan1 
22055dfd7cc4Ssstefan1   ChangeStatus updateImpl(Attributor &A) override {
22065dfd7cc4Ssstefan1     ChangeStatus Changed = ChangeStatus::UNCHANGED;
22075dfd7cc4Ssstefan1     const auto &ICVTrackingAA = A.getAAFor<AAICVTracker>(
22085b70c12fSJohannes Doerfert         *this, IRPosition::function(*getAnchorScope()), DepClassTy::REQUIRED);
22095dfd7cc4Ssstefan1 
22105dfd7cc4Ssstefan1     if (!ICVTrackingAA.isAssumedTracked())
22115dfd7cc4Ssstefan1       return indicatePessimisticFixpoint();
22125dfd7cc4Ssstefan1 
22135dfd7cc4Ssstefan1     for (InternalControlVar ICV : TrackableICVs) {
22145dfd7cc4Ssstefan1       Optional<Value *> &ReplVal = ICVReplacementValuesMap[ICV];
22155dfd7cc4Ssstefan1       Optional<Value *> UniqueICVValue;
22165dfd7cc4Ssstefan1 
22175dfd7cc4Ssstefan1       auto CheckReturnInst = [&](Instruction &I) {
22185dfd7cc4Ssstefan1         Optional<Value *> NewReplVal =
22195dfd7cc4Ssstefan1             ICVTrackingAA.getReplacementValue(ICV, &I, A);
22205dfd7cc4Ssstefan1 
22215dfd7cc4Ssstefan1         // If we found a second ICV value there is no unique returned value.
22225dfd7cc4Ssstefan1         if (UniqueICVValue.hasValue() && UniqueICVValue != NewReplVal)
22235dfd7cc4Ssstefan1           return false;
22245dfd7cc4Ssstefan1 
22255dfd7cc4Ssstefan1         UniqueICVValue = NewReplVal;
22265dfd7cc4Ssstefan1 
22275dfd7cc4Ssstefan1         return true;
22285dfd7cc4Ssstefan1       };
22295dfd7cc4Ssstefan1 
2230792aac98SJohannes Doerfert       bool UsedAssumedInformation = false;
22315dfd7cc4Ssstefan1       if (!A.checkForAllInstructions(CheckReturnInst, *this, {Instruction::Ret},
2232792aac98SJohannes Doerfert                                      UsedAssumedInformation,
22335dfd7cc4Ssstefan1                                      /* CheckBBLivenessOnly */ true))
22345dfd7cc4Ssstefan1         UniqueICVValue = nullptr;
22355dfd7cc4Ssstefan1 
22365dfd7cc4Ssstefan1       if (UniqueICVValue == ReplVal)
22375dfd7cc4Ssstefan1         continue;
22385dfd7cc4Ssstefan1 
22395dfd7cc4Ssstefan1       ReplVal = UniqueICVValue;
22405dfd7cc4Ssstefan1       Changed = ChangeStatus::CHANGED;
22415dfd7cc4Ssstefan1     }
22425dfd7cc4Ssstefan1 
22435dfd7cc4Ssstefan1     return Changed;
22445dfd7cc4Ssstefan1   }
22455dfd7cc4Ssstefan1 };
22465dfd7cc4Ssstefan1 
22475dfd7cc4Ssstefan1 struct AAICVTrackerCallSite : AAICVTracker {
22485dfd7cc4Ssstefan1   AAICVTrackerCallSite(const IRPosition &IRP, Attributor &A)
22495dfd7cc4Ssstefan1       : AAICVTracker(IRP, A) {}
22505dfd7cc4Ssstefan1 
22515dfd7cc4Ssstefan1   void initialize(Attributor &A) override {
22525dfd7cc4Ssstefan1     Function *F = getAnchorScope();
22535dfd7cc4Ssstefan1     if (!F || !A.isFunctionIPOAmendable(*F))
22545dfd7cc4Ssstefan1       indicatePessimisticFixpoint();
22555dfd7cc4Ssstefan1 
22565dfd7cc4Ssstefan1     // We only initialize this AA for getters, so we need to know which ICV it
22575dfd7cc4Ssstefan1     // gets.
22585dfd7cc4Ssstefan1     auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
22595dfd7cc4Ssstefan1     for (InternalControlVar ICV : TrackableICVs) {
22605dfd7cc4Ssstefan1       auto ICVInfo = OMPInfoCache.ICVs[ICV];
22615dfd7cc4Ssstefan1       auto &Getter = OMPInfoCache.RFIs[ICVInfo.Getter];
22625dfd7cc4Ssstefan1       if (Getter.Declaration == getAssociatedFunction()) {
22635dfd7cc4Ssstefan1         AssociatedICV = ICVInfo.Kind;
22645dfd7cc4Ssstefan1         return;
22655dfd7cc4Ssstefan1       }
22665dfd7cc4Ssstefan1     }
22675dfd7cc4Ssstefan1 
22685dfd7cc4Ssstefan1     /// Unknown ICV.
22695dfd7cc4Ssstefan1     indicatePessimisticFixpoint();
22705dfd7cc4Ssstefan1   }
22715dfd7cc4Ssstefan1 
22725dfd7cc4Ssstefan1   ChangeStatus manifest(Attributor &A) override {
22735dfd7cc4Ssstefan1     if (!ReplVal.hasValue() || !ReplVal.getValue())
22745dfd7cc4Ssstefan1       return ChangeStatus::UNCHANGED;
22755dfd7cc4Ssstefan1 
22765dfd7cc4Ssstefan1     A.changeValueAfterManifest(*getCtxI(), **ReplVal);
22775dfd7cc4Ssstefan1     A.deleteAfterManifest(*getCtxI());
22785dfd7cc4Ssstefan1 
22795dfd7cc4Ssstefan1     return ChangeStatus::CHANGED;
22805dfd7cc4Ssstefan1   }
22815dfd7cc4Ssstefan1 
22825dfd7cc4Ssstefan1   // FIXME: come up with better string.
22835dfd7cc4Ssstefan1   const std::string getAsStr() const override { return "ICVTrackerCallSite"; }
22845dfd7cc4Ssstefan1 
22855dfd7cc4Ssstefan1   // FIXME: come up with some stats.
22865dfd7cc4Ssstefan1   void trackStatistics() const override {}
22875dfd7cc4Ssstefan1 
22885dfd7cc4Ssstefan1   InternalControlVar AssociatedICV;
22895dfd7cc4Ssstefan1   Optional<Value *> ReplVal;
22905dfd7cc4Ssstefan1 
22915dfd7cc4Ssstefan1   ChangeStatus updateImpl(Attributor &A) override {
22925dfd7cc4Ssstefan1     const auto &ICVTrackingAA = A.getAAFor<AAICVTracker>(
22935b70c12fSJohannes Doerfert         *this, IRPosition::function(*getAnchorScope()), DepClassTy::REQUIRED);
22945dfd7cc4Ssstefan1 
22955dfd7cc4Ssstefan1     // We don't have any information, so we assume it changes the ICV.
22965dfd7cc4Ssstefan1     if (!ICVTrackingAA.isAssumedTracked())
22975dfd7cc4Ssstefan1       return indicatePessimisticFixpoint();
22985dfd7cc4Ssstefan1 
22995dfd7cc4Ssstefan1     Optional<Value *> NewReplVal =
23005dfd7cc4Ssstefan1         ICVTrackingAA.getReplacementValue(AssociatedICV, getCtxI(), A);
23015dfd7cc4Ssstefan1 
23025dfd7cc4Ssstefan1     if (ReplVal == NewReplVal)
23035dfd7cc4Ssstefan1       return ChangeStatus::UNCHANGED;
23045dfd7cc4Ssstefan1 
23055dfd7cc4Ssstefan1     ReplVal = NewReplVal;
23065dfd7cc4Ssstefan1     return ChangeStatus::CHANGED;
23075dfd7cc4Ssstefan1   }
23085dfd7cc4Ssstefan1 
23095dfd7cc4Ssstefan1   // Return the value with which associated value can be replaced for specific
23105dfd7cc4Ssstefan1   // \p ICV.
23115dfd7cc4Ssstefan1   Optional<Value *>
23125dfd7cc4Ssstefan1   getUniqueReplacementValue(InternalControlVar ICV) const override {
23135dfd7cc4Ssstefan1     return ReplVal;
23145dfd7cc4Ssstefan1   }
23155dfd7cc4Ssstefan1 };
23165dfd7cc4Ssstefan1 
23175dfd7cc4Ssstefan1 struct AAICVTrackerCallSiteReturned : AAICVTracker {
23185dfd7cc4Ssstefan1   AAICVTrackerCallSiteReturned(const IRPosition &IRP, Attributor &A)
23195dfd7cc4Ssstefan1       : AAICVTracker(IRP, A) {}
23205dfd7cc4Ssstefan1 
23215dfd7cc4Ssstefan1   // FIXME: come up with better string.
23225dfd7cc4Ssstefan1   const std::string getAsStr() const override {
23235dfd7cc4Ssstefan1     return "ICVTrackerCallSiteReturned";
23245dfd7cc4Ssstefan1   }
23255dfd7cc4Ssstefan1 
23265dfd7cc4Ssstefan1   // FIXME: come up with some stats.
23275dfd7cc4Ssstefan1   void trackStatistics() const override {}
23285dfd7cc4Ssstefan1 
23295dfd7cc4Ssstefan1   /// We don't manifest anything for this AA.
23305dfd7cc4Ssstefan1   ChangeStatus manifest(Attributor &A) override {
23315dfd7cc4Ssstefan1     return ChangeStatus::UNCHANGED;
23325dfd7cc4Ssstefan1   }
23335dfd7cc4Ssstefan1 
23345dfd7cc4Ssstefan1   // Map of ICV to their values at specific program point.
23355dfd7cc4Ssstefan1   EnumeratedArray<Optional<Value *>, InternalControlVar,
23365dfd7cc4Ssstefan1                   InternalControlVar::ICV___last>
23375dfd7cc4Ssstefan1       ICVReplacementValuesMap;
23385dfd7cc4Ssstefan1 
23395dfd7cc4Ssstefan1   /// Return the value with which associated value can be replaced for specific
23405dfd7cc4Ssstefan1   /// \p ICV.
23415dfd7cc4Ssstefan1   Optional<Value *>
23425dfd7cc4Ssstefan1   getUniqueReplacementValue(InternalControlVar ICV) const override {
23435dfd7cc4Ssstefan1     return ICVReplacementValuesMap[ICV];
23445dfd7cc4Ssstefan1   }
23455dfd7cc4Ssstefan1 
23465dfd7cc4Ssstefan1   ChangeStatus updateImpl(Attributor &A) override {
23475dfd7cc4Ssstefan1     ChangeStatus Changed = ChangeStatus::UNCHANGED;
23485dfd7cc4Ssstefan1     const auto &ICVTrackingAA = A.getAAFor<AAICVTracker>(
23495b70c12fSJohannes Doerfert         *this, IRPosition::returned(*getAssociatedFunction()),
23505b70c12fSJohannes Doerfert         DepClassTy::REQUIRED);
23515dfd7cc4Ssstefan1 
23525dfd7cc4Ssstefan1     // We don't have any information, so we assume it changes the ICV.
23535dfd7cc4Ssstefan1     if (!ICVTrackingAA.isAssumedTracked())
23545dfd7cc4Ssstefan1       return indicatePessimisticFixpoint();
23555dfd7cc4Ssstefan1 
23565dfd7cc4Ssstefan1     for (InternalControlVar ICV : TrackableICVs) {
23575dfd7cc4Ssstefan1       Optional<Value *> &ReplVal = ICVReplacementValuesMap[ICV];
23585dfd7cc4Ssstefan1       Optional<Value *> NewReplVal =
23595dfd7cc4Ssstefan1           ICVTrackingAA.getUniqueReplacementValue(ICV);
23605dfd7cc4Ssstefan1 
23615dfd7cc4Ssstefan1       if (ReplVal == NewReplVal)
23625dfd7cc4Ssstefan1         continue;
23635dfd7cc4Ssstefan1 
23645dfd7cc4Ssstefan1       ReplVal = NewReplVal;
23655dfd7cc4Ssstefan1       Changed = ChangeStatus::CHANGED;
23665dfd7cc4Ssstefan1     }
23675dfd7cc4Ssstefan1     return Changed;
23685dfd7cc4Ssstefan1   }
23699548b74aSJohannes Doerfert };
237018283125SJoseph Huber 
237118283125SJoseph Huber struct AAExecutionDomainFunction : public AAExecutionDomain {
237218283125SJoseph Huber   AAExecutionDomainFunction(const IRPosition &IRP, Attributor &A)
237318283125SJoseph Huber       : AAExecutionDomain(IRP, A) {}
237418283125SJoseph Huber 
237518283125SJoseph Huber   const std::string getAsStr() const override {
237618283125SJoseph Huber     return "[AAExecutionDomain] " + std::to_string(SingleThreadedBBs.size()) +
237718283125SJoseph Huber            "/" + std::to_string(NumBBs) + " BBs thread 0 only.";
237818283125SJoseph Huber   }
237918283125SJoseph Huber 
238018283125SJoseph Huber   /// See AbstractAttribute::trackStatistics().
238118283125SJoseph Huber   void trackStatistics() const override {}
238218283125SJoseph Huber 
238318283125SJoseph Huber   void initialize(Attributor &A) override {
238418283125SJoseph Huber     Function *F = getAnchorScope();
238518283125SJoseph Huber     for (const auto &BB : *F)
238618283125SJoseph Huber       SingleThreadedBBs.insert(&BB);
238718283125SJoseph Huber     NumBBs = SingleThreadedBBs.size();
238818283125SJoseph Huber   }
238918283125SJoseph Huber 
239018283125SJoseph Huber   ChangeStatus manifest(Attributor &A) override {
239118283125SJoseph Huber     LLVM_DEBUG({
239218283125SJoseph Huber       for (const BasicBlock *BB : SingleThreadedBBs)
239318283125SJoseph Huber         dbgs() << TAG << " Basic block @" << getAnchorScope()->getName() << " "
239418283125SJoseph Huber                << BB->getName() << " is executed by a single thread.\n";
239518283125SJoseph Huber     });
239618283125SJoseph Huber     return ChangeStatus::UNCHANGED;
239718283125SJoseph Huber   }
239818283125SJoseph Huber 
239918283125SJoseph Huber   ChangeStatus updateImpl(Attributor &A) override;
240018283125SJoseph Huber 
240118283125SJoseph Huber   /// Check if an instruction is executed by a single thread.
24029a23e673SJohannes Doerfert   bool isExecutedByInitialThreadOnly(const Instruction &I) const override {
24039a23e673SJohannes Doerfert     return isExecutedByInitialThreadOnly(*I.getParent());
240418283125SJoseph Huber   }
240518283125SJoseph Huber 
24069a23e673SJohannes Doerfert   bool isExecutedByInitialThreadOnly(const BasicBlock &BB) const override {
24071cfdcae6SJoseph Huber     return isValidState() && SingleThreadedBBs.contains(&BB);
240818283125SJoseph Huber   }
240918283125SJoseph Huber 
241018283125SJoseph Huber   /// Set of basic blocks that are executed by a single thread.
241118283125SJoseph Huber   DenseSet<const BasicBlock *> SingleThreadedBBs;
241218283125SJoseph Huber 
241318283125SJoseph Huber   /// Total number of basic blocks in this function.
241418283125SJoseph Huber   long unsigned NumBBs;
241518283125SJoseph Huber };
241618283125SJoseph Huber 
241718283125SJoseph Huber ChangeStatus AAExecutionDomainFunction::updateImpl(Attributor &A) {
241818283125SJoseph Huber   Function *F = getAnchorScope();
241918283125SJoseph Huber   ReversePostOrderTraversal<Function *> RPOT(F);
242018283125SJoseph Huber   auto NumSingleThreadedBBs = SingleThreadedBBs.size();
242118283125SJoseph Huber 
242218283125SJoseph Huber   bool AllCallSitesKnown;
242318283125SJoseph Huber   auto PredForCallSite = [&](AbstractCallSite ACS) {
242418283125SJoseph Huber     const auto &ExecutionDomainAA = A.getAAFor<AAExecutionDomain>(
242518283125SJoseph Huber         *this, IRPosition::function(*ACS.getInstruction()->getFunction()),
242618283125SJoseph Huber         DepClassTy::REQUIRED);
24271cfdcae6SJoseph Huber     return ACS.isDirectCall() &&
24281cfdcae6SJoseph Huber            ExecutionDomainAA.isExecutedByInitialThreadOnly(
24299a23e673SJohannes Doerfert                *ACS.getInstruction());
243018283125SJoseph Huber   };
243118283125SJoseph Huber 
243218283125SJoseph Huber   if (!A.checkForAllCallSites(PredForCallSite, *this,
243318283125SJoseph Huber                               /* RequiresAllCallSites */ true,
243418283125SJoseph Huber                               AllCallSitesKnown))
243518283125SJoseph Huber     SingleThreadedBBs.erase(&F->getEntryBlock());
243618283125SJoseph Huber 
2437e2cfbfccSJohannes Doerfert   auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
2438e2cfbfccSJohannes Doerfert   auto &RFI = OMPInfoCache.RFIs[OMPRTL___kmpc_target_init];
2439e2cfbfccSJohannes Doerfert 
2440e2cfbfccSJohannes Doerfert   // Check if the edge into the successor block compares the __kmpc_target_init
2441e2cfbfccSJohannes Doerfert   // result with -1. If we are in non-SPMD-mode that signals only the main
2442e2cfbfccSJohannes Doerfert   // thread will execute the edge.
24436fc51c9fSJoseph Huber   auto IsInitialThreadOnly = [&](BranchInst *Edge, BasicBlock *SuccessorBB) {
244418283125SJoseph Huber     if (!Edge || !Edge->isConditional())
244518283125SJoseph Huber       return false;
244618283125SJoseph Huber     if (Edge->getSuccessor(0) != SuccessorBB)
244718283125SJoseph Huber       return false;
244818283125SJoseph Huber 
244918283125SJoseph Huber     auto *Cmp = dyn_cast<CmpInst>(Edge->getCondition());
245018283125SJoseph Huber     if (!Cmp || !Cmp->isTrueWhenEqual() || !Cmp->isEquality())
245118283125SJoseph Huber       return false;
245218283125SJoseph Huber 
245318283125SJoseph Huber     ConstantInt *C = dyn_cast<ConstantInt>(Cmp->getOperand(1));
2454e2cfbfccSJohannes Doerfert     if (!C)
245518283125SJoseph Huber       return false;
245618283125SJoseph Huber 
2457e2cfbfccSJohannes Doerfert     // Match:  -1 == __kmpc_target_init (for non-SPMD kernels only!)
2458e2cfbfccSJohannes Doerfert     if (C->isAllOnesValue()) {
2459e2cfbfccSJohannes Doerfert       auto *CB = dyn_cast<CallBase>(Cmp->getOperand(0));
2460e2cfbfccSJohannes Doerfert       if (!CB || CB->getCalledFunction() != RFI.Declaration)
2461e2cfbfccSJohannes Doerfert         return false;
2462e2cfbfccSJohannes Doerfert       const int InitIsSPMDArgNo = 1;
2463e2cfbfccSJohannes Doerfert       auto *IsSPMDModeCI =
2464e2cfbfccSJohannes Doerfert           dyn_cast<ConstantInt>(CB->getOperand(InitIsSPMDArgNo));
2465e2cfbfccSJohannes Doerfert       return IsSPMDModeCI && IsSPMDModeCI->isZero();
2466e2cfbfccSJohannes Doerfert     }
246718283125SJoseph Huber 
246818283125SJoseph Huber     return false;
246918283125SJoseph Huber   };
247018283125SJoseph Huber 
247118283125SJoseph Huber   // Merge all the predecessor states into the current basic block. A basic
247218283125SJoseph Huber   // block is executed by a single thread if all of its predecessors are.
247318283125SJoseph Huber   auto MergePredecessorStates = [&](BasicBlock *BB) {
247418283125SJoseph Huber     if (pred_begin(BB) == pred_end(BB))
247518283125SJoseph Huber       return SingleThreadedBBs.contains(BB);
247618283125SJoseph Huber 
24776fc51c9fSJoseph Huber     bool IsInitialThread = true;
247818283125SJoseph Huber     for (auto PredBB = pred_begin(BB), PredEndBB = pred_end(BB);
247918283125SJoseph Huber          PredBB != PredEndBB; ++PredBB) {
24806fc51c9fSJoseph Huber       if (!IsInitialThreadOnly(dyn_cast<BranchInst>((*PredBB)->getTerminator()),
248118283125SJoseph Huber                                BB))
24826fc51c9fSJoseph Huber         IsInitialThread &= SingleThreadedBBs.contains(*PredBB);
248318283125SJoseph Huber     }
248418283125SJoseph Huber 
24856fc51c9fSJoseph Huber     return IsInitialThread;
248618283125SJoseph Huber   };
248718283125SJoseph Huber 
248818283125SJoseph Huber   for (auto *BB : RPOT) {
248918283125SJoseph Huber     if (!MergePredecessorStates(BB))
249018283125SJoseph Huber       SingleThreadedBBs.erase(BB);
249118283125SJoseph Huber   }
249218283125SJoseph Huber 
249318283125SJoseph Huber   return (NumSingleThreadedBBs == SingleThreadedBBs.size())
249418283125SJoseph Huber              ? ChangeStatus::UNCHANGED
249518283125SJoseph Huber              : ChangeStatus::CHANGED;
249618283125SJoseph Huber }
249718283125SJoseph Huber 
24986fc51c9fSJoseph Huber /// Try to replace memory allocation calls called by a single thread with a
24996fc51c9fSJoseph Huber /// static buffer of shared memory.
25006fc51c9fSJoseph Huber struct AAHeapToShared : public StateWrapper<BooleanState, AbstractAttribute> {
25016fc51c9fSJoseph Huber   using Base = StateWrapper<BooleanState, AbstractAttribute>;
25026fc51c9fSJoseph Huber   AAHeapToShared(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
25036fc51c9fSJoseph Huber 
25046fc51c9fSJoseph Huber   /// Create an abstract attribute view for the position \p IRP.
25056fc51c9fSJoseph Huber   static AAHeapToShared &createForPosition(const IRPosition &IRP,
25066fc51c9fSJoseph Huber                                            Attributor &A);
25076fc51c9fSJoseph Huber 
25086fc51c9fSJoseph Huber   /// See AbstractAttribute::getName().
25096fc51c9fSJoseph Huber   const std::string getName() const override { return "AAHeapToShared"; }
25106fc51c9fSJoseph Huber 
25116fc51c9fSJoseph Huber   /// See AbstractAttribute::getIdAddr().
25126fc51c9fSJoseph Huber   const char *getIdAddr() const override { return &ID; }
25136fc51c9fSJoseph Huber 
25146fc51c9fSJoseph Huber   /// This function should return true if the type of the \p AA is
25156fc51c9fSJoseph Huber   /// AAHeapToShared.
25166fc51c9fSJoseph Huber   static bool classof(const AbstractAttribute *AA) {
25176fc51c9fSJoseph Huber     return (AA->getIdAddr() == &ID);
25186fc51c9fSJoseph Huber   }
25196fc51c9fSJoseph Huber 
25206fc51c9fSJoseph Huber   /// Unique ID (due to the unique address)
25216fc51c9fSJoseph Huber   static const char ID;
25226fc51c9fSJoseph Huber };
25236fc51c9fSJoseph Huber 
25246fc51c9fSJoseph Huber struct AAHeapToSharedFunction : public AAHeapToShared {
25256fc51c9fSJoseph Huber   AAHeapToSharedFunction(const IRPosition &IRP, Attributor &A)
25266fc51c9fSJoseph Huber       : AAHeapToShared(IRP, A) {}
25276fc51c9fSJoseph Huber 
25286fc51c9fSJoseph Huber   const std::string getAsStr() const override {
25296fc51c9fSJoseph Huber     return "[AAHeapToShared] " + std::to_string(MallocCalls.size()) +
25306fc51c9fSJoseph Huber            " malloc calls eligible.";
25316fc51c9fSJoseph Huber   }
25326fc51c9fSJoseph Huber 
25336fc51c9fSJoseph Huber   /// See AbstractAttribute::trackStatistics().
25346fc51c9fSJoseph Huber   void trackStatistics() const override {}
25356fc51c9fSJoseph Huber 
25366fc51c9fSJoseph Huber   void initialize(Attributor &A) override {
25376fc51c9fSJoseph Huber     auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
25386fc51c9fSJoseph Huber     auto &RFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
25396fc51c9fSJoseph Huber 
25406fc51c9fSJoseph Huber     for (User *U : RFI.Declaration->users())
25416fc51c9fSJoseph Huber       if (CallBase *CB = dyn_cast<CallBase>(U))
25426fc51c9fSJoseph Huber         MallocCalls.insert(CB);
25436fc51c9fSJoseph Huber   }
25446fc51c9fSJoseph Huber 
25456fc51c9fSJoseph Huber   ChangeStatus manifest(Attributor &A) override {
25466fc51c9fSJoseph Huber     if (MallocCalls.empty())
25476fc51c9fSJoseph Huber       return ChangeStatus::UNCHANGED;
25486fc51c9fSJoseph Huber 
25496fc51c9fSJoseph Huber     auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
25506fc51c9fSJoseph Huber     auto &FreeCall = OMPInfoCache.RFIs[OMPRTL___kmpc_free_shared];
25516fc51c9fSJoseph Huber 
25526fc51c9fSJoseph Huber     Function *F = getAnchorScope();
25536fc51c9fSJoseph Huber     auto *HS = A.lookupAAFor<AAHeapToStack>(IRPosition::function(*F), this,
25546fc51c9fSJoseph Huber                                             DepClassTy::OPTIONAL);
25556fc51c9fSJoseph Huber 
25566fc51c9fSJoseph Huber     ChangeStatus Changed = ChangeStatus::UNCHANGED;
25576fc51c9fSJoseph Huber     for (CallBase *CB : MallocCalls) {
25586fc51c9fSJoseph Huber       // Skip replacing this if HeapToStack has already claimed it.
2559c1c1fe93SJohannes Doerfert       if (HS && HS->isAssumedHeapToStack(*CB))
25606fc51c9fSJoseph Huber         continue;
25616fc51c9fSJoseph Huber 
25626fc51c9fSJoseph Huber       // Find the unique free call to remove it.
25636fc51c9fSJoseph Huber       SmallVector<CallBase *, 4> FreeCalls;
25646fc51c9fSJoseph Huber       for (auto *U : CB->users()) {
25656fc51c9fSJoseph Huber         CallBase *C = dyn_cast<CallBase>(U);
25666fc51c9fSJoseph Huber         if (C && C->getCalledFunction() == FreeCall.Declaration)
25676fc51c9fSJoseph Huber           FreeCalls.push_back(C);
25686fc51c9fSJoseph Huber       }
25696fc51c9fSJoseph Huber       if (FreeCalls.size() != 1)
25706fc51c9fSJoseph Huber         continue;
25716fc51c9fSJoseph Huber 
25726fc51c9fSJoseph Huber       ConstantInt *AllocSize = dyn_cast<ConstantInt>(CB->getArgOperand(0));
25736fc51c9fSJoseph Huber 
25746fc51c9fSJoseph Huber       LLVM_DEBUG(dbgs() << TAG << "Replace globalization call in "
25756fc51c9fSJoseph Huber                         << CB->getCaller()->getName() << " with "
25766fc51c9fSJoseph Huber                         << AllocSize->getZExtValue()
25776fc51c9fSJoseph Huber                         << " bytes of shared memory\n");
25786fc51c9fSJoseph Huber 
25796fc51c9fSJoseph Huber       // Create a new shared memory buffer of the same size as the allocation
25806fc51c9fSJoseph Huber       // and replace all the uses of the original allocation with it.
25816fc51c9fSJoseph Huber       Module *M = CB->getModule();
25826fc51c9fSJoseph Huber       Type *Int8Ty = Type::getInt8Ty(M->getContext());
25836fc51c9fSJoseph Huber       Type *Int8ArrTy = ArrayType::get(Int8Ty, AllocSize->getZExtValue());
25846fc51c9fSJoseph Huber       auto *SharedMem = new GlobalVariable(
25856fc51c9fSJoseph Huber           *M, Int8ArrTy, /* IsConstant */ false, GlobalValue::InternalLinkage,
25866fc51c9fSJoseph Huber           UndefValue::get(Int8ArrTy), CB->getName(), nullptr,
25876fc51c9fSJoseph Huber           GlobalValue::NotThreadLocal,
25886fc51c9fSJoseph Huber           static_cast<unsigned>(AddressSpace::Shared));
25896fc51c9fSJoseph Huber       auto *NewBuffer =
25906fc51c9fSJoseph Huber           ConstantExpr::getPointerCast(SharedMem, Int8Ty->getPointerTo());
25916fc51c9fSJoseph Huber 
259230e36c9bSJoseph Huber       auto Remark = [&](OptimizationRemark OR) {
259330e36c9bSJoseph Huber         return OR << "Replaced globalized variable with "
259430e36c9bSJoseph Huber                   << ore::NV("SharedMemory", AllocSize->getZExtValue())
259530e36c9bSJoseph Huber                   << ((AllocSize->getZExtValue() != 1) ? " bytes " : " byte ")
2596eef6601bSJoseph Huber                   << "of shared memory.";
259730e36c9bSJoseph Huber       };
25982c31d5ebSJoseph Huber       A.emitRemark<OptimizationRemark>(CB, "OMP111", Remark);
259930e36c9bSJoseph Huber 
26006fc51c9fSJoseph Huber       SharedMem->setAlignment(MaybeAlign(32));
26016fc51c9fSJoseph Huber 
26026fc51c9fSJoseph Huber       A.changeValueAfterManifest(*CB, *NewBuffer);
26036fc51c9fSJoseph Huber       A.deleteAfterManifest(*CB);
26046fc51c9fSJoseph Huber       A.deleteAfterManifest(*FreeCalls.front());
26056fc51c9fSJoseph Huber 
26066fc51c9fSJoseph Huber       NumBytesMovedToSharedMemory += AllocSize->getZExtValue();
26076fc51c9fSJoseph Huber       Changed = ChangeStatus::CHANGED;
26086fc51c9fSJoseph Huber     }
26096fc51c9fSJoseph Huber 
26106fc51c9fSJoseph Huber     return Changed;
26116fc51c9fSJoseph Huber   }
26126fc51c9fSJoseph Huber 
26136fc51c9fSJoseph Huber   ChangeStatus updateImpl(Attributor &A) override {
26146fc51c9fSJoseph Huber     auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
26156fc51c9fSJoseph Huber     auto &RFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
26166fc51c9fSJoseph Huber     Function *F = getAnchorScope();
26176fc51c9fSJoseph Huber 
26186fc51c9fSJoseph Huber     auto NumMallocCalls = MallocCalls.size();
26196fc51c9fSJoseph Huber 
26206fc51c9fSJoseph Huber     // Only consider malloc calls executed by a single thread with a constant.
26216fc51c9fSJoseph Huber     for (User *U : RFI.Declaration->users()) {
26226fc51c9fSJoseph Huber       const auto &ED = A.getAAFor<AAExecutionDomain>(
26236fc51c9fSJoseph Huber           *this, IRPosition::function(*F), DepClassTy::REQUIRED);
26246fc51c9fSJoseph Huber       if (CallBase *CB = dyn_cast<CallBase>(U))
26256fc51c9fSJoseph Huber         if (!dyn_cast<ConstantInt>(CB->getArgOperand(0)) ||
26266fc51c9fSJoseph Huber             !ED.isExecutedByInitialThreadOnly(*CB))
26276fc51c9fSJoseph Huber           MallocCalls.erase(CB);
26286fc51c9fSJoseph Huber     }
26296fc51c9fSJoseph Huber 
26306fc51c9fSJoseph Huber     if (NumMallocCalls != MallocCalls.size())
26316fc51c9fSJoseph Huber       return ChangeStatus::CHANGED;
26326fc51c9fSJoseph Huber 
26336fc51c9fSJoseph Huber     return ChangeStatus::UNCHANGED;
26346fc51c9fSJoseph Huber   }
26356fc51c9fSJoseph Huber 
26366fc51c9fSJoseph Huber   /// Collection of all malloc calls in a function.
26376fc51c9fSJoseph Huber   SmallPtrSet<CallBase *, 4> MallocCalls;
26386fc51c9fSJoseph Huber };
26396fc51c9fSJoseph Huber 
2640d9659bf6SJohannes Doerfert struct AAKernelInfo : public StateWrapper<KernelInfoState, AbstractAttribute> {
2641d9659bf6SJohannes Doerfert   using Base = StateWrapper<KernelInfoState, AbstractAttribute>;
2642d9659bf6SJohannes Doerfert   AAKernelInfo(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
2643d9659bf6SJohannes Doerfert 
2644d9659bf6SJohannes Doerfert   /// Statistics are tracked as part of manifest for now.
2645d9659bf6SJohannes Doerfert   void trackStatistics() const override {}
2646d9659bf6SJohannes Doerfert 
2647d9659bf6SJohannes Doerfert   /// See AbstractAttribute::getAsStr()
2648d9659bf6SJohannes Doerfert   const std::string getAsStr() const override {
2649d9659bf6SJohannes Doerfert     if (!isValidState())
2650d9659bf6SJohannes Doerfert       return "<invalid>";
2651514c033dSJohannes Doerfert     return std::string(SPMDCompatibilityTracker.isAssumed() ? "SPMD"
2652514c033dSJohannes Doerfert                                                             : "generic") +
2653514c033dSJohannes Doerfert            std::string(SPMDCompatibilityTracker.isAtFixpoint() ? " [FIX]"
2654514c033dSJohannes Doerfert                                                                : "") +
2655d9659bf6SJohannes Doerfert            std::string(" #PRs: ") +
2656d9659bf6SJohannes Doerfert            std::to_string(ReachedKnownParallelRegions.size()) +
2657d9659bf6SJohannes Doerfert            ", #Unknown PRs: " +
2658d9659bf6SJohannes Doerfert            std::to_string(ReachedUnknownParallelRegions.size());
2659d9659bf6SJohannes Doerfert   }
2660d9659bf6SJohannes Doerfert 
2661d9659bf6SJohannes Doerfert   /// Create an abstract attribute biew for the position \p IRP.
2662d9659bf6SJohannes Doerfert   static AAKernelInfo &createForPosition(const IRPosition &IRP, Attributor &A);
2663d9659bf6SJohannes Doerfert 
2664d9659bf6SJohannes Doerfert   /// See AbstractAttribute::getName()
2665d9659bf6SJohannes Doerfert   const std::string getName() const override { return "AAKernelInfo"; }
2666d9659bf6SJohannes Doerfert 
2667d9659bf6SJohannes Doerfert   /// See AbstractAttribute::getIdAddr()
2668d9659bf6SJohannes Doerfert   const char *getIdAddr() const override { return &ID; }
2669d9659bf6SJohannes Doerfert 
2670d9659bf6SJohannes Doerfert   /// This function should return true if the type of the \p AA is AAKernelInfo
2671d9659bf6SJohannes Doerfert   static bool classof(const AbstractAttribute *AA) {
2672d9659bf6SJohannes Doerfert     return (AA->getIdAddr() == &ID);
2673d9659bf6SJohannes Doerfert   }
2674d9659bf6SJohannes Doerfert 
2675d9659bf6SJohannes Doerfert   static const char ID;
2676d9659bf6SJohannes Doerfert };
2677d9659bf6SJohannes Doerfert 
2678d9659bf6SJohannes Doerfert /// The function kernel info abstract attribute, basically, what can we say
2679d9659bf6SJohannes Doerfert /// about a function with regards to the KernelInfoState.
2680d9659bf6SJohannes Doerfert struct AAKernelInfoFunction : AAKernelInfo {
2681d9659bf6SJohannes Doerfert   AAKernelInfoFunction(const IRPosition &IRP, Attributor &A)
2682d9659bf6SJohannes Doerfert       : AAKernelInfo(IRP, A) {}
2683d9659bf6SJohannes Doerfert 
2684d9659bf6SJohannes Doerfert   /// See AbstractAttribute::initialize(...).
2685d9659bf6SJohannes Doerfert   void initialize(Attributor &A) override {
2686d9659bf6SJohannes Doerfert     // This is a high-level transform that might change the constant arguments
2687d9659bf6SJohannes Doerfert     // of the init and dinit calls. We need to tell the Attributor about this
2688d9659bf6SJohannes Doerfert     // to avoid other parts using the current constant value for simpliication.
2689d9659bf6SJohannes Doerfert     auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
2690d9659bf6SJohannes Doerfert 
2691d9659bf6SJohannes Doerfert     Function *Fn = getAnchorScope();
2692d9659bf6SJohannes Doerfert     if (!OMPInfoCache.Kernels.count(Fn))
2693d9659bf6SJohannes Doerfert       return;
2694d9659bf6SJohannes Doerfert 
2695ca662297SShilei Tian     // Add itself to the reaching kernel and set IsKernelEntry.
2696ca662297SShilei Tian     ReachingKernelEntries.insert(Fn);
2697ca662297SShilei Tian     IsKernelEntry = true;
2698ca662297SShilei Tian 
2699d9659bf6SJohannes Doerfert     OMPInformationCache::RuntimeFunctionInfo &InitRFI =
2700d9659bf6SJohannes Doerfert         OMPInfoCache.RFIs[OMPRTL___kmpc_target_init];
2701d9659bf6SJohannes Doerfert     OMPInformationCache::RuntimeFunctionInfo &DeinitRFI =
2702d9659bf6SJohannes Doerfert         OMPInfoCache.RFIs[OMPRTL___kmpc_target_deinit];
2703d9659bf6SJohannes Doerfert 
2704d9659bf6SJohannes Doerfert     // For kernels we perform more initialization work, first we find the init
2705d9659bf6SJohannes Doerfert     // and deinit calls.
2706d9659bf6SJohannes Doerfert     auto StoreCallBase = [](Use &U,
2707d9659bf6SJohannes Doerfert                             OMPInformationCache::RuntimeFunctionInfo &RFI,
2708d9659bf6SJohannes Doerfert                             CallBase *&Storage) {
2709d9659bf6SJohannes Doerfert       CallBase *CB = OpenMPOpt::getCallIfRegularCall(U, &RFI);
2710d9659bf6SJohannes Doerfert       assert(CB &&
2711d9659bf6SJohannes Doerfert              "Unexpected use of __kmpc_target_init or __kmpc_target_deinit!");
2712d9659bf6SJohannes Doerfert       assert(!Storage &&
2713d9659bf6SJohannes Doerfert              "Multiple uses of __kmpc_target_init or __kmpc_target_deinit!");
2714d9659bf6SJohannes Doerfert       Storage = CB;
2715d9659bf6SJohannes Doerfert       return false;
2716d9659bf6SJohannes Doerfert     };
2717d9659bf6SJohannes Doerfert     InitRFI.foreachUse(
2718d9659bf6SJohannes Doerfert         [&](Use &U, Function &) {
2719d9659bf6SJohannes Doerfert           StoreCallBase(U, InitRFI, KernelInitCB);
2720d9659bf6SJohannes Doerfert           return false;
2721d9659bf6SJohannes Doerfert         },
2722d9659bf6SJohannes Doerfert         Fn);
2723d9659bf6SJohannes Doerfert     DeinitRFI.foreachUse(
2724d9659bf6SJohannes Doerfert         [&](Use &U, Function &) {
2725d9659bf6SJohannes Doerfert           StoreCallBase(U, DeinitRFI, KernelDeinitCB);
2726d9659bf6SJohannes Doerfert           return false;
2727d9659bf6SJohannes Doerfert         },
2728d9659bf6SJohannes Doerfert         Fn);
2729d9659bf6SJohannes Doerfert 
2730d9659bf6SJohannes Doerfert     assert((KernelInitCB && KernelDeinitCB) &&
2731d9659bf6SJohannes Doerfert            "Kernel without __kmpc_target_init or __kmpc_target_deinit!");
2732d9659bf6SJohannes Doerfert 
2733514c033dSJohannes Doerfert     // For kernels we might need to initialize/finalize the IsSPMD state and
2734514c033dSJohannes Doerfert     // we need to register a simplification callback so that the Attributor
2735514c033dSJohannes Doerfert     // knows the constant arguments to __kmpc_target_init and
2736d9659bf6SJohannes Doerfert     // __kmpc_target_deinit might actually change.
2737d9659bf6SJohannes Doerfert 
2738d9659bf6SJohannes Doerfert     Attributor::SimplifictionCallbackTy StateMachineSimplifyCB =
2739d9659bf6SJohannes Doerfert         [&](const IRPosition &IRP, const AbstractAttribute *AA,
2740d9659bf6SJohannes Doerfert             bool &UsedAssumedInformation) -> Optional<Value *> {
2741d9659bf6SJohannes Doerfert       // IRP represents the "use generic state machine" argument of an
2742d9659bf6SJohannes Doerfert       // __kmpc_target_init call. We will answer this one with the internal
2743d9659bf6SJohannes Doerfert       // state. As long as we are not in an invalid state, we will create a
2744d9659bf6SJohannes Doerfert       // custom state machine so the value should be a `i1 false`. If we are
2745d9659bf6SJohannes Doerfert       // in an invalid state, we won't change the value that is in the IR.
2746d9659bf6SJohannes Doerfert       if (!isValidState())
2747d9659bf6SJohannes Doerfert         return nullptr;
2748d9659bf6SJohannes Doerfert       if (AA)
2749d9659bf6SJohannes Doerfert         A.recordDependence(*this, *AA, DepClassTy::OPTIONAL);
2750d9659bf6SJohannes Doerfert       UsedAssumedInformation = !isAtFixpoint();
2751d9659bf6SJohannes Doerfert       auto *FalseVal =
2752d9659bf6SJohannes Doerfert           ConstantInt::getBool(IRP.getAnchorValue().getContext(), 0);
2753d9659bf6SJohannes Doerfert       return FalseVal;
2754d9659bf6SJohannes Doerfert     };
2755d9659bf6SJohannes Doerfert 
2756514c033dSJohannes Doerfert     Attributor::SimplifictionCallbackTy IsSPMDModeSimplifyCB =
2757514c033dSJohannes Doerfert         [&](const IRPosition &IRP, const AbstractAttribute *AA,
2758514c033dSJohannes Doerfert             bool &UsedAssumedInformation) -> Optional<Value *> {
2759514c033dSJohannes Doerfert       // IRP represents the "SPMDCompatibilityTracker" argument of an
2760514c033dSJohannes Doerfert       // __kmpc_target_init or
2761514c033dSJohannes Doerfert       // __kmpc_target_deinit call. We will answer this one with the internal
2762514c033dSJohannes Doerfert       // state.
276397387fdfSJohannes Doerfert       if (!SPMDCompatibilityTracker.isValidState())
2764514c033dSJohannes Doerfert         return nullptr;
2765514c033dSJohannes Doerfert       if (!SPMDCompatibilityTracker.isAtFixpoint()) {
2766514c033dSJohannes Doerfert         if (AA)
2767514c033dSJohannes Doerfert           A.recordDependence(*this, *AA, DepClassTy::OPTIONAL);
2768514c033dSJohannes Doerfert         UsedAssumedInformation = true;
2769514c033dSJohannes Doerfert       } else {
2770514c033dSJohannes Doerfert         UsedAssumedInformation = false;
2771514c033dSJohannes Doerfert       }
2772514c033dSJohannes Doerfert       auto *Val = ConstantInt::getBool(IRP.getAnchorValue().getContext(),
2773514c033dSJohannes Doerfert                                        SPMDCompatibilityTracker.isAssumed());
2774514c033dSJohannes Doerfert       return Val;
2775514c033dSJohannes Doerfert     };
2776514c033dSJohannes Doerfert 
2777e8439ec8SGiorgis Georgakoudis     Attributor::SimplifictionCallbackTy IsGenericModeSimplifyCB =
2778e8439ec8SGiorgis Georgakoudis         [&](const IRPosition &IRP, const AbstractAttribute *AA,
2779e8439ec8SGiorgis Georgakoudis             bool &UsedAssumedInformation) -> Optional<Value *> {
2780e8439ec8SGiorgis Georgakoudis       // IRP represents the "RequiresFullRuntime" argument of an
2781e8439ec8SGiorgis Georgakoudis       // __kmpc_target_init or __kmpc_target_deinit call. We will answer this
2782e8439ec8SGiorgis Georgakoudis       // one with the internal state of the SPMDCompatibilityTracker, so if
2783e8439ec8SGiorgis Georgakoudis       // generic then true, if SPMD then false.
2784e8439ec8SGiorgis Georgakoudis       if (!SPMDCompatibilityTracker.isValidState())
2785e8439ec8SGiorgis Georgakoudis         return nullptr;
2786e8439ec8SGiorgis Georgakoudis       if (!SPMDCompatibilityTracker.isAtFixpoint()) {
2787e8439ec8SGiorgis Georgakoudis         if (AA)
2788e8439ec8SGiorgis Georgakoudis           A.recordDependence(*this, *AA, DepClassTy::OPTIONAL);
2789e8439ec8SGiorgis Georgakoudis         UsedAssumedInformation = true;
2790e8439ec8SGiorgis Georgakoudis       } else {
2791e8439ec8SGiorgis Georgakoudis         UsedAssumedInformation = false;
2792e8439ec8SGiorgis Georgakoudis       }
2793e8439ec8SGiorgis Georgakoudis       auto *Val = ConstantInt::getBool(IRP.getAnchorValue().getContext(),
2794e8439ec8SGiorgis Georgakoudis                                        !SPMDCompatibilityTracker.isAssumed());
2795e8439ec8SGiorgis Georgakoudis       return Val;
2796e8439ec8SGiorgis Georgakoudis     };
2797e8439ec8SGiorgis Georgakoudis 
2798514c033dSJohannes Doerfert     constexpr const int InitIsSPMDArgNo = 1;
2799514c033dSJohannes Doerfert     constexpr const int DeinitIsSPMDArgNo = 1;
2800d9659bf6SJohannes Doerfert     constexpr const int InitUseStateMachineArgNo = 2;
2801e8439ec8SGiorgis Georgakoudis     constexpr const int InitRequiresFullRuntimeArgNo = 3;
2802e8439ec8SGiorgis Georgakoudis     constexpr const int DeinitRequiresFullRuntimeArgNo = 2;
2803d9659bf6SJohannes Doerfert     A.registerSimplificationCallback(
2804d9659bf6SJohannes Doerfert         IRPosition::callsite_argument(*KernelInitCB, InitUseStateMachineArgNo),
2805d9659bf6SJohannes Doerfert         StateMachineSimplifyCB);
2806514c033dSJohannes Doerfert     A.registerSimplificationCallback(
2807514c033dSJohannes Doerfert         IRPosition::callsite_argument(*KernelInitCB, InitIsSPMDArgNo),
2808514c033dSJohannes Doerfert         IsSPMDModeSimplifyCB);
2809514c033dSJohannes Doerfert     A.registerSimplificationCallback(
2810514c033dSJohannes Doerfert         IRPosition::callsite_argument(*KernelDeinitCB, DeinitIsSPMDArgNo),
2811514c033dSJohannes Doerfert         IsSPMDModeSimplifyCB);
2812e8439ec8SGiorgis Georgakoudis     A.registerSimplificationCallback(
2813e8439ec8SGiorgis Georgakoudis         IRPosition::callsite_argument(*KernelInitCB,
2814e8439ec8SGiorgis Georgakoudis                                       InitRequiresFullRuntimeArgNo),
2815e8439ec8SGiorgis Georgakoudis         IsGenericModeSimplifyCB);
2816e8439ec8SGiorgis Georgakoudis     A.registerSimplificationCallback(
2817e8439ec8SGiorgis Georgakoudis         IRPosition::callsite_argument(*KernelDeinitCB,
2818e8439ec8SGiorgis Georgakoudis                                       DeinitRequiresFullRuntimeArgNo),
2819e8439ec8SGiorgis Georgakoudis         IsGenericModeSimplifyCB);
2820514c033dSJohannes Doerfert 
2821514c033dSJohannes Doerfert     // Check if we know we are in SPMD-mode already.
2822514c033dSJohannes Doerfert     ConstantInt *IsSPMDArg =
2823514c033dSJohannes Doerfert         dyn_cast<ConstantInt>(KernelInitCB->getArgOperand(InitIsSPMDArgNo));
2824514c033dSJohannes Doerfert     if (IsSPMDArg && !IsSPMDArg->isZero())
2825514c033dSJohannes Doerfert       SPMDCompatibilityTracker.indicateOptimisticFixpoint();
2826d9659bf6SJohannes Doerfert   }
2827d9659bf6SJohannes Doerfert 
2828d9659bf6SJohannes Doerfert   /// Modify the IR based on the KernelInfoState as the fixpoint iteration is
2829d9659bf6SJohannes Doerfert   /// finished now.
2830d9659bf6SJohannes Doerfert   ChangeStatus manifest(Attributor &A) override {
2831d9659bf6SJohannes Doerfert     // If we are not looking at a kernel with __kmpc_target_init and
2832d9659bf6SJohannes Doerfert     // __kmpc_target_deinit call we cannot actually manifest the information.
2833d9659bf6SJohannes Doerfert     if (!KernelInitCB || !KernelDeinitCB)
2834d9659bf6SJohannes Doerfert       return ChangeStatus::UNCHANGED;
2835d9659bf6SJohannes Doerfert 
2836514c033dSJohannes Doerfert     // Known SPMD-mode kernels need no manifest changes.
2837514c033dSJohannes Doerfert     if (SPMDCompatibilityTracker.isKnown())
2838514c033dSJohannes Doerfert       return ChangeStatus::UNCHANGED;
2839514c033dSJohannes Doerfert 
2840514c033dSJohannes Doerfert     // If we can we change the execution mode to SPMD-mode otherwise we build a
2841514c033dSJohannes Doerfert     // custom state machine.
2842514c033dSJohannes Doerfert     if (!changeToSPMDMode(A))
2843d9659bf6SJohannes Doerfert       buildCustomStateMachine(A);
2844d9659bf6SJohannes Doerfert 
2845d9659bf6SJohannes Doerfert     return ChangeStatus::CHANGED;
2846d9659bf6SJohannes Doerfert   }
2847d9659bf6SJohannes Doerfert 
2848514c033dSJohannes Doerfert   bool changeToSPMDMode(Attributor &A) {
2849eef6601bSJoseph Huber     auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
2850eef6601bSJoseph Huber 
2851514c033dSJohannes Doerfert     if (!SPMDCompatibilityTracker.isAssumed()) {
2852514c033dSJohannes Doerfert       for (Instruction *NonCompatibleI : SPMDCompatibilityTracker) {
2853514c033dSJohannes Doerfert         if (!NonCompatibleI)
2854514c033dSJohannes Doerfert           continue;
2855eef6601bSJoseph Huber 
2856eef6601bSJoseph Huber         // Skip diagnostics on calls to known OpenMP runtime functions for now.
2857eef6601bSJoseph Huber         if (auto *CB = dyn_cast<CallBase>(NonCompatibleI))
2858eef6601bSJoseph Huber           if (OMPInfoCache.RTLFunctions.contains(CB->getCalledFunction()))
2859eef6601bSJoseph Huber             continue;
2860eef6601bSJoseph Huber 
2861514c033dSJohannes Doerfert         auto Remark = [&](OptimizationRemarkAnalysis ORA) {
2862eef6601bSJoseph Huber           ORA << "Value has potential side effects preventing SPMD-mode "
2863eef6601bSJoseph Huber                  "execution";
2864eef6601bSJoseph Huber           if (isa<CallBase>(NonCompatibleI)) {
2865eef6601bSJoseph Huber             ORA << ". Add `__attribute__((assume(\"ompx_spmd_amenable\")))` to "
2866eef6601bSJoseph Huber                    "the called function to override";
2867514c033dSJohannes Doerfert           }
2868514c033dSJohannes Doerfert           return ORA << ".";
2869514c033dSJohannes Doerfert         };
28702c31d5ebSJoseph Huber         A.emitRemark<OptimizationRemarkAnalysis>(NonCompatibleI, "OMP121",
28712c31d5ebSJoseph Huber                                                  Remark);
2872514c033dSJohannes Doerfert 
2873514c033dSJohannes Doerfert         LLVM_DEBUG(dbgs() << TAG << "SPMD-incompatible side-effect: "
2874514c033dSJohannes Doerfert                           << *NonCompatibleI << "\n");
2875514c033dSJohannes Doerfert       }
2876514c033dSJohannes Doerfert 
2877514c033dSJohannes Doerfert       return false;
2878514c033dSJohannes Doerfert     }
2879514c033dSJohannes Doerfert 
2880514c033dSJohannes Doerfert     // Adjust the global exec mode flag that tells the runtime what mode this
2881514c033dSJohannes Doerfert     // kernel is executed in.
2882514c033dSJohannes Doerfert     Function *Kernel = getAnchorScope();
2883514c033dSJohannes Doerfert     GlobalVariable *ExecMode = Kernel->getParent()->getGlobalVariable(
2884514c033dSJohannes Doerfert         (Kernel->getName() + "_exec_mode").str());
2885514c033dSJohannes Doerfert     assert(ExecMode && "Kernel without exec mode?");
2886514c033dSJohannes Doerfert     assert(ExecMode->getInitializer() &&
2887514c033dSJohannes Doerfert            ExecMode->getInitializer()->isOneValue() &&
2888514c033dSJohannes Doerfert            "Initially non-SPMD kernel has SPMD exec mode!");
2889*7d576392SJoseph Huber 
2890*7d576392SJoseph Huber     // Set the global exec mode flag to indicate SPMD-Generic mode.
2891*7d576392SJoseph Huber     constexpr int SPMDGeneric = 2;
2892*7d576392SJoseph Huber     if (!ExecMode->getInitializer()->isZeroValue())
2893514c033dSJohannes Doerfert       ExecMode->setInitializer(
2894*7d576392SJoseph Huber           ConstantInt::get(ExecMode->getInitializer()->getType(), SPMDGeneric));
2895514c033dSJohannes Doerfert 
2896514c033dSJohannes Doerfert     // Next rewrite the init and deinit calls to indicate we use SPMD-mode now.
2897514c033dSJohannes Doerfert     const int InitIsSPMDArgNo = 1;
2898514c033dSJohannes Doerfert     const int DeinitIsSPMDArgNo = 1;
2899514c033dSJohannes Doerfert     const int InitUseStateMachineArgNo = 2;
2900e8439ec8SGiorgis Georgakoudis     const int InitRequiresFullRuntimeArgNo = 3;
2901e8439ec8SGiorgis Georgakoudis     const int DeinitRequiresFullRuntimeArgNo = 2;
2902514c033dSJohannes Doerfert 
2903514c033dSJohannes Doerfert     auto &Ctx = getAnchorValue().getContext();
2904514c033dSJohannes Doerfert     A.changeUseAfterManifest(KernelInitCB->getArgOperandUse(InitIsSPMDArgNo),
2905514c033dSJohannes Doerfert                              *ConstantInt::getBool(Ctx, 1));
2906514c033dSJohannes Doerfert     A.changeUseAfterManifest(
2907514c033dSJohannes Doerfert         KernelInitCB->getArgOperandUse(InitUseStateMachineArgNo),
2908514c033dSJohannes Doerfert         *ConstantInt::getBool(Ctx, 0));
2909514c033dSJohannes Doerfert     A.changeUseAfterManifest(
2910514c033dSJohannes Doerfert         KernelDeinitCB->getArgOperandUse(DeinitIsSPMDArgNo),
2911514c033dSJohannes Doerfert         *ConstantInt::getBool(Ctx, 1));
2912e8439ec8SGiorgis Georgakoudis     A.changeUseAfterManifest(
2913e8439ec8SGiorgis Georgakoudis         KernelInitCB->getArgOperandUse(InitRequiresFullRuntimeArgNo),
2914e8439ec8SGiorgis Georgakoudis         *ConstantInt::getBool(Ctx, 0));
2915e8439ec8SGiorgis Georgakoudis     A.changeUseAfterManifest(
2916e8439ec8SGiorgis Georgakoudis         KernelDeinitCB->getArgOperandUse(DeinitRequiresFullRuntimeArgNo),
2917e8439ec8SGiorgis Georgakoudis         *ConstantInt::getBool(Ctx, 0));
2918e8439ec8SGiorgis Georgakoudis 
2919514c033dSJohannes Doerfert     ++NumOpenMPTargetRegionKernelsSPMD;
2920514c033dSJohannes Doerfert 
2921514c033dSJohannes Doerfert     auto Remark = [&](OptimizationRemark OR) {
2922eef6601bSJoseph Huber       return OR << "Transformed generic-mode kernel to SPMD-mode.";
2923514c033dSJohannes Doerfert     };
29242c31d5ebSJoseph Huber     A.emitRemark<OptimizationRemark>(KernelInitCB, "OMP120", Remark);
2925514c033dSJohannes Doerfert     return true;
2926514c033dSJohannes Doerfert   };
2927514c033dSJohannes Doerfert 
2928d9659bf6SJohannes Doerfert   ChangeStatus buildCustomStateMachine(Attributor &A) {
2929d9659bf6SJohannes Doerfert     assert(ReachedKnownParallelRegions.isValidState() &&
2930d9659bf6SJohannes Doerfert            "Custom state machine with invalid parallel region states?");
2931d9659bf6SJohannes Doerfert 
2932d9659bf6SJohannes Doerfert     const int InitIsSPMDArgNo = 1;
2933d9659bf6SJohannes Doerfert     const int InitUseStateMachineArgNo = 2;
2934d9659bf6SJohannes Doerfert 
2935d9659bf6SJohannes Doerfert     // Check if the current configuration is non-SPMD and generic state machine.
2936d9659bf6SJohannes Doerfert     // If we already have SPMD mode or a custom state machine we do not need to
2937d9659bf6SJohannes Doerfert     // go any further. If it is anything but a constant something is weird and
2938d9659bf6SJohannes Doerfert     // we give up.
2939d9659bf6SJohannes Doerfert     ConstantInt *UseStateMachine = dyn_cast<ConstantInt>(
2940d9659bf6SJohannes Doerfert         KernelInitCB->getArgOperand(InitUseStateMachineArgNo));
2941d9659bf6SJohannes Doerfert     ConstantInt *IsSPMD =
2942d9659bf6SJohannes Doerfert         dyn_cast<ConstantInt>(KernelInitCB->getArgOperand(InitIsSPMDArgNo));
2943d9659bf6SJohannes Doerfert 
2944d9659bf6SJohannes Doerfert     // If we are stuck with generic mode, try to create a custom device (=GPU)
2945d9659bf6SJohannes Doerfert     // state machine which is specialized for the parallel regions that are
2946d9659bf6SJohannes Doerfert     // reachable by the kernel.
2947d9659bf6SJohannes Doerfert     if (!UseStateMachine || UseStateMachine->isZero() || !IsSPMD ||
2948d9659bf6SJohannes Doerfert         !IsSPMD->isZero())
2949d9659bf6SJohannes Doerfert       return ChangeStatus::UNCHANGED;
2950d9659bf6SJohannes Doerfert 
2951514c033dSJohannes Doerfert     // If not SPMD mode, indicate we use a custom state machine now.
2952d9659bf6SJohannes Doerfert     auto &Ctx = getAnchorValue().getContext();
2953d9659bf6SJohannes Doerfert     auto *FalseVal = ConstantInt::getBool(Ctx, 0);
2954d9659bf6SJohannes Doerfert     A.changeUseAfterManifest(
2955d9659bf6SJohannes Doerfert         KernelInitCB->getArgOperandUse(InitUseStateMachineArgNo), *FalseVal);
2956d9659bf6SJohannes Doerfert 
2957d9659bf6SJohannes Doerfert     // If we don't actually need a state machine we are done here. This can
2958d9659bf6SJohannes Doerfert     // happen if there simply are no parallel regions. In the resulting kernel
2959d9659bf6SJohannes Doerfert     // all worker threads will simply exit right away, leaving the main thread
2960d9659bf6SJohannes Doerfert     // to do the work alone.
2961d9659bf6SJohannes Doerfert     if (ReachedKnownParallelRegions.empty() &&
2962d9659bf6SJohannes Doerfert         ReachedUnknownParallelRegions.empty()) {
2963d9659bf6SJohannes Doerfert       ++NumOpenMPTargetRegionKernelsWithoutStateMachine;
2964d9659bf6SJohannes Doerfert 
2965d9659bf6SJohannes Doerfert       auto Remark = [&](OptimizationRemark OR) {
2966eef6601bSJoseph Huber         return OR << "Removing unused state machine from generic-mode kernel.";
2967d9659bf6SJohannes Doerfert       };
29682c31d5ebSJoseph Huber       A.emitRemark<OptimizationRemark>(KernelInitCB, "OMP130", Remark);
2969d9659bf6SJohannes Doerfert 
2970d9659bf6SJohannes Doerfert       return ChangeStatus::CHANGED;
2971d9659bf6SJohannes Doerfert     }
2972d9659bf6SJohannes Doerfert 
2973d9659bf6SJohannes Doerfert     // Keep track in the statistics of our new shiny custom state machine.
2974d9659bf6SJohannes Doerfert     if (ReachedUnknownParallelRegions.empty()) {
2975d9659bf6SJohannes Doerfert       ++NumOpenMPTargetRegionKernelsCustomStateMachineWithoutFallback;
2976d9659bf6SJohannes Doerfert 
2977d9659bf6SJohannes Doerfert       auto Remark = [&](OptimizationRemark OR) {
2978eef6601bSJoseph Huber         return OR << "Rewriting generic-mode kernel with a customized state "
2979eef6601bSJoseph Huber                      "machine.";
2980d9659bf6SJohannes Doerfert       };
29812c31d5ebSJoseph Huber       A.emitRemark<OptimizationRemark>(KernelInitCB, "OMP131", Remark);
2982d9659bf6SJohannes Doerfert     } else {
2983d9659bf6SJohannes Doerfert       ++NumOpenMPTargetRegionKernelsCustomStateMachineWithFallback;
2984d9659bf6SJohannes Doerfert 
2985eef6601bSJoseph Huber       auto Remark = [&](OptimizationRemarkAnalysis OR) {
2986d9659bf6SJohannes Doerfert         return OR << "Generic-mode kernel is executed with a customized state "
2987eef6601bSJoseph Huber                      "machine that requires a fallback.";
2988d9659bf6SJohannes Doerfert       };
29892c31d5ebSJoseph Huber       A.emitRemark<OptimizationRemarkAnalysis>(KernelInitCB, "OMP132", Remark);
2990d9659bf6SJohannes Doerfert 
2991d9659bf6SJohannes Doerfert       // Tell the user why we ended up with a fallback.
2992d9659bf6SJohannes Doerfert       for (CallBase *UnknownParallelRegionCB : ReachedUnknownParallelRegions) {
2993d9659bf6SJohannes Doerfert         if (!UnknownParallelRegionCB)
2994d9659bf6SJohannes Doerfert           continue;
2995d9659bf6SJohannes Doerfert         auto Remark = [&](OptimizationRemarkAnalysis ORA) {
2996eef6601bSJoseph Huber           return ORA << "Call may contain unknown parallel regions. Use "
2997eef6601bSJoseph Huber                      << "`__attribute__((assume(\"omp_no_parallelism\")))` to "
2998eef6601bSJoseph Huber                         "override.";
2999d9659bf6SJohannes Doerfert         };
30002c31d5ebSJoseph Huber         A.emitRemark<OptimizationRemarkAnalysis>(UnknownParallelRegionCB,
30012c31d5ebSJoseph Huber                                                  "OMP133", Remark);
3002d9659bf6SJohannes Doerfert       }
3003d9659bf6SJohannes Doerfert     }
3004d9659bf6SJohannes Doerfert 
3005d9659bf6SJohannes Doerfert     // Create all the blocks:
3006d9659bf6SJohannes Doerfert     //
3007d9659bf6SJohannes Doerfert     //                       InitCB = __kmpc_target_init(...)
3008d9659bf6SJohannes Doerfert     //                       bool IsWorker = InitCB >= 0;
3009d9659bf6SJohannes Doerfert     //                       if (IsWorker) {
3010d9659bf6SJohannes Doerfert     // SMBeginBB:               __kmpc_barrier_simple_spmd(...);
3011d9659bf6SJohannes Doerfert     //                         void *WorkFn;
3012d9659bf6SJohannes Doerfert     //                         bool Active = __kmpc_kernel_parallel(&WorkFn);
3013d9659bf6SJohannes Doerfert     //                         if (!WorkFn) return;
3014d9659bf6SJohannes Doerfert     // SMIsActiveCheckBB:       if (Active) {
3015d9659bf6SJohannes Doerfert     // SMIfCascadeCurrentBB:      if      (WorkFn == <ParFn0>)
3016d9659bf6SJohannes Doerfert     //                              ParFn0(...);
3017d9659bf6SJohannes Doerfert     // SMIfCascadeCurrentBB:      else if (WorkFn == <ParFn1>)
3018d9659bf6SJohannes Doerfert     //                              ParFn1(...);
3019d9659bf6SJohannes Doerfert     //                            ...
3020d9659bf6SJohannes Doerfert     // SMIfCascadeCurrentBB:      else
3021d9659bf6SJohannes Doerfert     //                              ((WorkFnTy*)WorkFn)(...);
3022d9659bf6SJohannes Doerfert     // SMEndParallelBB:           __kmpc_kernel_end_parallel(...);
3023d9659bf6SJohannes Doerfert     //                          }
3024d9659bf6SJohannes Doerfert     // SMDoneBB:                __kmpc_barrier_simple_spmd(...);
3025d9659bf6SJohannes Doerfert     //                          goto SMBeginBB;
3026d9659bf6SJohannes Doerfert     //                       }
3027d9659bf6SJohannes Doerfert     // UserCodeEntryBB:      // user code
3028d9659bf6SJohannes Doerfert     //                       __kmpc_target_deinit(...)
3029d9659bf6SJohannes Doerfert     //
3030d9659bf6SJohannes Doerfert     Function *Kernel = getAssociatedFunction();
3031d9659bf6SJohannes Doerfert     assert(Kernel && "Expected an associated function!");
3032d9659bf6SJohannes Doerfert 
3033d9659bf6SJohannes Doerfert     BasicBlock *InitBB = KernelInitCB->getParent();
3034d9659bf6SJohannes Doerfert     BasicBlock *UserCodeEntryBB = InitBB->splitBasicBlock(
3035d9659bf6SJohannes Doerfert         KernelInitCB->getNextNode(), "thread.user_code.check");
3036d9659bf6SJohannes Doerfert     BasicBlock *StateMachineBeginBB = BasicBlock::Create(
3037d9659bf6SJohannes Doerfert         Ctx, "worker_state_machine.begin", Kernel, UserCodeEntryBB);
3038d9659bf6SJohannes Doerfert     BasicBlock *StateMachineFinishedBB = BasicBlock::Create(
3039d9659bf6SJohannes Doerfert         Ctx, "worker_state_machine.finished", Kernel, UserCodeEntryBB);
3040d9659bf6SJohannes Doerfert     BasicBlock *StateMachineIsActiveCheckBB = BasicBlock::Create(
3041d9659bf6SJohannes Doerfert         Ctx, "worker_state_machine.is_active.check", Kernel, UserCodeEntryBB);
3042d9659bf6SJohannes Doerfert     BasicBlock *StateMachineIfCascadeCurrentBB =
3043d9659bf6SJohannes Doerfert         BasicBlock::Create(Ctx, "worker_state_machine.parallel_region.check",
3044d9659bf6SJohannes Doerfert                            Kernel, UserCodeEntryBB);
3045d9659bf6SJohannes Doerfert     BasicBlock *StateMachineEndParallelBB =
3046d9659bf6SJohannes Doerfert         BasicBlock::Create(Ctx, "worker_state_machine.parallel_region.end",
3047d9659bf6SJohannes Doerfert                            Kernel, UserCodeEntryBB);
3048d9659bf6SJohannes Doerfert     BasicBlock *StateMachineDoneBarrierBB = BasicBlock::Create(
3049d9659bf6SJohannes Doerfert         Ctx, "worker_state_machine.done.barrier", Kernel, UserCodeEntryBB);
30503f71b425SGiorgis Georgakoudis     A.registerManifestAddedBasicBlock(*InitBB);
30513f71b425SGiorgis Georgakoudis     A.registerManifestAddedBasicBlock(*UserCodeEntryBB);
30523f71b425SGiorgis Georgakoudis     A.registerManifestAddedBasicBlock(*StateMachineBeginBB);
30533f71b425SGiorgis Georgakoudis     A.registerManifestAddedBasicBlock(*StateMachineFinishedBB);
30543f71b425SGiorgis Georgakoudis     A.registerManifestAddedBasicBlock(*StateMachineIsActiveCheckBB);
30553f71b425SGiorgis Georgakoudis     A.registerManifestAddedBasicBlock(*StateMachineIfCascadeCurrentBB);
30563f71b425SGiorgis Georgakoudis     A.registerManifestAddedBasicBlock(*StateMachineEndParallelBB);
30573f71b425SGiorgis Georgakoudis     A.registerManifestAddedBasicBlock(*StateMachineDoneBarrierBB);
3058d9659bf6SJohannes Doerfert 
3059d9659bf6SJohannes Doerfert     const DebugLoc &DLoc = KernelInitCB->getDebugLoc();
3060d9659bf6SJohannes Doerfert     ReturnInst::Create(Ctx, StateMachineFinishedBB)->setDebugLoc(DLoc);
3061d9659bf6SJohannes Doerfert 
3062d9659bf6SJohannes Doerfert     InitBB->getTerminator()->eraseFromParent();
3063d9659bf6SJohannes Doerfert     Instruction *IsWorker =
3064d9659bf6SJohannes Doerfert         ICmpInst::Create(ICmpInst::ICmp, llvm::CmpInst::ICMP_NE, KernelInitCB,
3065d9659bf6SJohannes Doerfert                          ConstantInt::get(KernelInitCB->getType(), -1),
3066d9659bf6SJohannes Doerfert                          "thread.is_worker", InitBB);
3067d9659bf6SJohannes Doerfert     IsWorker->setDebugLoc(DLoc);
3068d9659bf6SJohannes Doerfert     BranchInst::Create(StateMachineBeginBB, UserCodeEntryBB, IsWorker, InitBB);
3069d9659bf6SJohannes Doerfert 
3070d9659bf6SJohannes Doerfert     // Create local storage for the work function pointer.
3071d9659bf6SJohannes Doerfert     Type *VoidPtrTy = Type::getInt8PtrTy(Ctx);
3072d9659bf6SJohannes Doerfert     AllocaInst *WorkFnAI = new AllocaInst(VoidPtrTy, 0, "worker.work_fn.addr",
3073d9659bf6SJohannes Doerfert                                           &Kernel->getEntryBlock().front());
3074d9659bf6SJohannes Doerfert     WorkFnAI->setDebugLoc(DLoc);
3075d9659bf6SJohannes Doerfert 
3076d9659bf6SJohannes Doerfert     auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
3077d9659bf6SJohannes Doerfert     OMPInfoCache.OMPBuilder.updateToLocation(
3078d9659bf6SJohannes Doerfert         OpenMPIRBuilder::LocationDescription(
3079d9659bf6SJohannes Doerfert             IRBuilder<>::InsertPoint(StateMachineBeginBB,
3080d9659bf6SJohannes Doerfert                                      StateMachineBeginBB->end()),
3081d9659bf6SJohannes Doerfert             DLoc));
3082d9659bf6SJohannes Doerfert 
3083d9659bf6SJohannes Doerfert     Value *Ident = KernelInitCB->getArgOperand(0);
3084d9659bf6SJohannes Doerfert     Value *GTid = KernelInitCB;
3085d9659bf6SJohannes Doerfert 
3086d9659bf6SJohannes Doerfert     Module &M = *Kernel->getParent();
3087d9659bf6SJohannes Doerfert     FunctionCallee BarrierFn =
3088d9659bf6SJohannes Doerfert         OMPInfoCache.OMPBuilder.getOrCreateRuntimeFunction(
3089d9659bf6SJohannes Doerfert             M, OMPRTL___kmpc_barrier_simple_spmd);
3090d9659bf6SJohannes Doerfert     CallInst::Create(BarrierFn, {Ident, GTid}, "", StateMachineBeginBB)
3091d9659bf6SJohannes Doerfert         ->setDebugLoc(DLoc);
3092d9659bf6SJohannes Doerfert 
3093d9659bf6SJohannes Doerfert     FunctionCallee KernelParallelFn =
3094d9659bf6SJohannes Doerfert         OMPInfoCache.OMPBuilder.getOrCreateRuntimeFunction(
3095d9659bf6SJohannes Doerfert             M, OMPRTL___kmpc_kernel_parallel);
3096d9659bf6SJohannes Doerfert     Instruction *IsActiveWorker = CallInst::Create(
3097d9659bf6SJohannes Doerfert         KernelParallelFn, {WorkFnAI}, "worker.is_active", StateMachineBeginBB);
3098d9659bf6SJohannes Doerfert     IsActiveWorker->setDebugLoc(DLoc);
3099d9659bf6SJohannes Doerfert     Instruction *WorkFn = new LoadInst(VoidPtrTy, WorkFnAI, "worker.work_fn",
3100d9659bf6SJohannes Doerfert                                        StateMachineBeginBB);
3101d9659bf6SJohannes Doerfert     WorkFn->setDebugLoc(DLoc);
3102d9659bf6SJohannes Doerfert 
3103d9659bf6SJohannes Doerfert     FunctionType *ParallelRegionFnTy = FunctionType::get(
3104d9659bf6SJohannes Doerfert         Type::getVoidTy(Ctx), {Type::getInt16Ty(Ctx), Type::getInt32Ty(Ctx)},
3105d9659bf6SJohannes Doerfert         false);
3106d9659bf6SJohannes Doerfert     Value *WorkFnCast = BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
3107d9659bf6SJohannes Doerfert         WorkFn, ParallelRegionFnTy->getPointerTo(), "worker.work_fn.addr_cast",
3108d9659bf6SJohannes Doerfert         StateMachineBeginBB);
3109d9659bf6SJohannes Doerfert 
3110d9659bf6SJohannes Doerfert     Instruction *IsDone =
3111d9659bf6SJohannes Doerfert         ICmpInst::Create(ICmpInst::ICmp, llvm::CmpInst::ICMP_EQ, WorkFn,
3112d9659bf6SJohannes Doerfert                          Constant::getNullValue(VoidPtrTy), "worker.is_done",
3113d9659bf6SJohannes Doerfert                          StateMachineBeginBB);
3114d9659bf6SJohannes Doerfert     IsDone->setDebugLoc(DLoc);
3115d9659bf6SJohannes Doerfert     BranchInst::Create(StateMachineFinishedBB, StateMachineIsActiveCheckBB,
3116d9659bf6SJohannes Doerfert                        IsDone, StateMachineBeginBB)
3117d9659bf6SJohannes Doerfert         ->setDebugLoc(DLoc);
3118d9659bf6SJohannes Doerfert 
3119d9659bf6SJohannes Doerfert     BranchInst::Create(StateMachineIfCascadeCurrentBB,
3120d9659bf6SJohannes Doerfert                        StateMachineDoneBarrierBB, IsActiveWorker,
3121d9659bf6SJohannes Doerfert                        StateMachineIsActiveCheckBB)
3122d9659bf6SJohannes Doerfert         ->setDebugLoc(DLoc);
3123d9659bf6SJohannes Doerfert 
3124d9659bf6SJohannes Doerfert     Value *ZeroArg =
3125d9659bf6SJohannes Doerfert         Constant::getNullValue(ParallelRegionFnTy->getParamType(0));
3126d9659bf6SJohannes Doerfert 
3127d9659bf6SJohannes Doerfert     // Now that we have most of the CFG skeleton it is time for the if-cascade
3128d9659bf6SJohannes Doerfert     // that checks the function pointer we got from the runtime against the
3129d9659bf6SJohannes Doerfert     // parallel regions we expect, if there are any.
3130d9659bf6SJohannes Doerfert     for (int i = 0, e = ReachedKnownParallelRegions.size(); i < e; ++i) {
3131d9659bf6SJohannes Doerfert       auto *ParallelRegion = ReachedKnownParallelRegions[i];
3132d9659bf6SJohannes Doerfert       BasicBlock *PRExecuteBB = BasicBlock::Create(
3133d9659bf6SJohannes Doerfert           Ctx, "worker_state_machine.parallel_region.execute", Kernel,
3134d9659bf6SJohannes Doerfert           StateMachineEndParallelBB);
3135d9659bf6SJohannes Doerfert       CallInst::Create(ParallelRegion, {ZeroArg, GTid}, "", PRExecuteBB)
3136d9659bf6SJohannes Doerfert           ->setDebugLoc(DLoc);
3137d9659bf6SJohannes Doerfert       BranchInst::Create(StateMachineEndParallelBB, PRExecuteBB)
3138d9659bf6SJohannes Doerfert           ->setDebugLoc(DLoc);
3139d9659bf6SJohannes Doerfert 
3140d9659bf6SJohannes Doerfert       BasicBlock *PRNextBB =
3141d9659bf6SJohannes Doerfert           BasicBlock::Create(Ctx, "worker_state_machine.parallel_region.check",
3142d9659bf6SJohannes Doerfert                              Kernel, StateMachineEndParallelBB);
3143d9659bf6SJohannes Doerfert 
3144d9659bf6SJohannes Doerfert       // Check if we need to compare the pointer at all or if we can just
3145d9659bf6SJohannes Doerfert       // call the parallel region function.
3146d9659bf6SJohannes Doerfert       Value *IsPR;
3147d9659bf6SJohannes Doerfert       if (i + 1 < e || !ReachedUnknownParallelRegions.empty()) {
3148d9659bf6SJohannes Doerfert         Instruction *CmpI = ICmpInst::Create(
3149d9659bf6SJohannes Doerfert             ICmpInst::ICmp, llvm::CmpInst::ICMP_EQ, WorkFnCast, ParallelRegion,
3150d9659bf6SJohannes Doerfert             "worker.check_parallel_region", StateMachineIfCascadeCurrentBB);
3151d9659bf6SJohannes Doerfert         CmpI->setDebugLoc(DLoc);
3152d9659bf6SJohannes Doerfert         IsPR = CmpI;
3153d9659bf6SJohannes Doerfert       } else {
3154d9659bf6SJohannes Doerfert         IsPR = ConstantInt::getTrue(Ctx);
3155d9659bf6SJohannes Doerfert       }
3156d9659bf6SJohannes Doerfert 
3157d9659bf6SJohannes Doerfert       BranchInst::Create(PRExecuteBB, PRNextBB, IsPR,
3158d9659bf6SJohannes Doerfert                          StateMachineIfCascadeCurrentBB)
3159d9659bf6SJohannes Doerfert           ->setDebugLoc(DLoc);
3160d9659bf6SJohannes Doerfert       StateMachineIfCascadeCurrentBB = PRNextBB;
3161d9659bf6SJohannes Doerfert     }
3162d9659bf6SJohannes Doerfert 
3163d9659bf6SJohannes Doerfert     // At the end of the if-cascade we place the indirect function pointer call
3164d9659bf6SJohannes Doerfert     // in case we might need it, that is if there can be parallel regions we
3165d9659bf6SJohannes Doerfert     // have not handled in the if-cascade above.
3166d9659bf6SJohannes Doerfert     if (!ReachedUnknownParallelRegions.empty()) {
3167d9659bf6SJohannes Doerfert       StateMachineIfCascadeCurrentBB->setName(
3168d9659bf6SJohannes Doerfert           "worker_state_machine.parallel_region.fallback.execute");
3169d9659bf6SJohannes Doerfert       CallInst::Create(ParallelRegionFnTy, WorkFnCast, {ZeroArg, GTid}, "",
3170d9659bf6SJohannes Doerfert                        StateMachineIfCascadeCurrentBB)
3171d9659bf6SJohannes Doerfert           ->setDebugLoc(DLoc);
3172d9659bf6SJohannes Doerfert     }
3173d9659bf6SJohannes Doerfert     BranchInst::Create(StateMachineEndParallelBB,
3174d9659bf6SJohannes Doerfert                        StateMachineIfCascadeCurrentBB)
3175d9659bf6SJohannes Doerfert         ->setDebugLoc(DLoc);
3176d9659bf6SJohannes Doerfert 
3177d9659bf6SJohannes Doerfert     CallInst::Create(OMPInfoCache.OMPBuilder.getOrCreateRuntimeFunction(
3178d9659bf6SJohannes Doerfert                          M, OMPRTL___kmpc_kernel_end_parallel),
3179d9659bf6SJohannes Doerfert                      {}, "", StateMachineEndParallelBB)
3180d9659bf6SJohannes Doerfert         ->setDebugLoc(DLoc);
3181d9659bf6SJohannes Doerfert     BranchInst::Create(StateMachineDoneBarrierBB, StateMachineEndParallelBB)
3182d9659bf6SJohannes Doerfert         ->setDebugLoc(DLoc);
3183d9659bf6SJohannes Doerfert 
3184d9659bf6SJohannes Doerfert     CallInst::Create(BarrierFn, {Ident, GTid}, "", StateMachineDoneBarrierBB)
3185d9659bf6SJohannes Doerfert         ->setDebugLoc(DLoc);
3186d9659bf6SJohannes Doerfert     BranchInst::Create(StateMachineBeginBB, StateMachineDoneBarrierBB)
3187d9659bf6SJohannes Doerfert         ->setDebugLoc(DLoc);
3188d9659bf6SJohannes Doerfert 
3189d9659bf6SJohannes Doerfert     return ChangeStatus::CHANGED;
3190d9659bf6SJohannes Doerfert   }
3191d9659bf6SJohannes Doerfert 
3192d9659bf6SJohannes Doerfert   /// Fixpoint iteration update function. Will be called every time a dependence
3193d9659bf6SJohannes Doerfert   /// changed its state (and in the beginning).
3194d9659bf6SJohannes Doerfert   ChangeStatus updateImpl(Attributor &A) override {
3195d9659bf6SJohannes Doerfert     KernelInfoState StateBefore = getState();
3196d9659bf6SJohannes Doerfert 
3197514c033dSJohannes Doerfert     // Callback to check a read/write instruction.
3198514c033dSJohannes Doerfert     auto CheckRWInst = [&](Instruction &I) {
3199514c033dSJohannes Doerfert       // We handle calls later.
3200514c033dSJohannes Doerfert       if (isa<CallBase>(I))
3201514c033dSJohannes Doerfert         return true;
3202514c033dSJohannes Doerfert       // We only care about write effects.
3203514c033dSJohannes Doerfert       if (!I.mayWriteToMemory())
3204514c033dSJohannes Doerfert         return true;
3205514c033dSJohannes Doerfert       if (auto *SI = dyn_cast<StoreInst>(&I)) {
3206514c033dSJohannes Doerfert         SmallVector<const Value *> Objects;
3207514c033dSJohannes Doerfert         getUnderlyingObjects(SI->getPointerOperand(), Objects);
3208514c033dSJohannes Doerfert         if (llvm::all_of(Objects,
3209514c033dSJohannes Doerfert                          [](const Value *Obj) { return isa<AllocaInst>(Obj); }))
3210514c033dSJohannes Doerfert           return true;
3211514c033dSJohannes Doerfert       }
3212514c033dSJohannes Doerfert       // For now we give up on everything but stores.
3213514c033dSJohannes Doerfert       SPMDCompatibilityTracker.insert(&I);
3214514c033dSJohannes Doerfert       return true;
3215514c033dSJohannes Doerfert     };
3216792aac98SJohannes Doerfert 
3217792aac98SJohannes Doerfert     bool UsedAssumedInformationInCheckRWInst = false;
321897387fdfSJohannes Doerfert     if (!SPMDCompatibilityTracker.isAtFixpoint())
3219792aac98SJohannes Doerfert       if (!A.checkForAllReadWriteInstructions(
3220792aac98SJohannes Doerfert               CheckRWInst, *this, UsedAssumedInformationInCheckRWInst))
3221514c033dSJohannes Doerfert         SPMDCompatibilityTracker.indicatePessimisticFixpoint();
3222514c033dSJohannes Doerfert 
3223ca662297SShilei Tian     if (!IsKernelEntry)
3224ca662297SShilei Tian       updateReachingKernelEntries(A);
3225ca662297SShilei Tian 
3226d9659bf6SJohannes Doerfert     // Callback to check a call instruction.
322797387fdfSJohannes Doerfert     bool AllSPMDStatesWereFixed = true;
3228d9659bf6SJohannes Doerfert     auto CheckCallInst = [&](Instruction &I) {
3229d9659bf6SJohannes Doerfert       auto &CB = cast<CallBase>(I);
3230d9659bf6SJohannes Doerfert       auto &CBAA = A.getAAFor<AAKernelInfo>(
3231d9659bf6SJohannes Doerfert           *this, IRPosition::callsite_function(CB), DepClassTy::OPTIONAL);
3232d9659bf6SJohannes Doerfert       getState() ^= CBAA.getState();
323397387fdfSJohannes Doerfert       AllSPMDStatesWereFixed &= CBAA.SPMDCompatibilityTracker.isAtFixpoint();
3234d9659bf6SJohannes Doerfert       return true;
3235d9659bf6SJohannes Doerfert     };
3236d9659bf6SJohannes Doerfert 
3237792aac98SJohannes Doerfert     bool UsedAssumedInformationInCheckCallInst = false;
3238792aac98SJohannes Doerfert     if (!A.checkForAllCallLikeInstructions(
3239792aac98SJohannes Doerfert             CheckCallInst, *this, UsedAssumedInformationInCheckCallInst))
3240d9659bf6SJohannes Doerfert       return indicatePessimisticFixpoint();
3241d9659bf6SJohannes Doerfert 
324297387fdfSJohannes Doerfert     // If we haven't used any assumed information for the SPMD state we can fix
324397387fdfSJohannes Doerfert     // it.
324497387fdfSJohannes Doerfert     if (!UsedAssumedInformationInCheckRWInst &&
324597387fdfSJohannes Doerfert         !UsedAssumedInformationInCheckCallInst && AllSPMDStatesWereFixed)
324697387fdfSJohannes Doerfert       SPMDCompatibilityTracker.indicateOptimisticFixpoint();
324797387fdfSJohannes Doerfert 
3248d9659bf6SJohannes Doerfert     return StateBefore == getState() ? ChangeStatus::UNCHANGED
3249d9659bf6SJohannes Doerfert                                      : ChangeStatus::CHANGED;
3250d9659bf6SJohannes Doerfert   }
3251ca662297SShilei Tian 
3252ca662297SShilei Tian private:
3253ca662297SShilei Tian   /// Update info regarding reaching kernels.
3254ca662297SShilei Tian   void updateReachingKernelEntries(Attributor &A) {
3255ca662297SShilei Tian     auto PredCallSite = [&](AbstractCallSite ACS) {
3256ca662297SShilei Tian       Function *Caller = ACS.getInstruction()->getFunction();
3257ca662297SShilei Tian 
3258ca662297SShilei Tian       assert(Caller && "Caller is nullptr");
3259ca662297SShilei Tian 
3260d3454ee8SShilei Tian       auto &CAA = A.getOrCreateAAFor<AAKernelInfo>(
3261d3454ee8SShilei Tian           IRPosition::function(*Caller), this, DepClassTy::REQUIRED);
3262ca662297SShilei Tian       if (CAA.ReachingKernelEntries.isValidState()) {
3263ca662297SShilei Tian         ReachingKernelEntries ^= CAA.ReachingKernelEntries;
3264ca662297SShilei Tian         return true;
3265ca662297SShilei Tian       }
3266ca662297SShilei Tian 
3267ca662297SShilei Tian       // We lost track of the caller of the associated function, any kernel
3268ca662297SShilei Tian       // could reach now.
3269ca662297SShilei Tian       ReachingKernelEntries.indicatePessimisticFixpoint();
3270ca662297SShilei Tian 
3271ca662297SShilei Tian       return true;
3272ca662297SShilei Tian     };
3273ca662297SShilei Tian 
3274ca662297SShilei Tian     bool AllCallSitesKnown;
3275ca662297SShilei Tian     if (!A.checkForAllCallSites(PredCallSite, *this,
3276ca662297SShilei Tian                                 true /* RequireAllCallSites */,
3277ca662297SShilei Tian                                 AllCallSitesKnown))
3278ca662297SShilei Tian       ReachingKernelEntries.indicatePessimisticFixpoint();
3279ca662297SShilei Tian   }
3280d9659bf6SJohannes Doerfert };
3281d9659bf6SJohannes Doerfert 
3282d9659bf6SJohannes Doerfert /// The call site kernel info abstract attribute, basically, what can we say
3283d9659bf6SJohannes Doerfert /// about a call site with regards to the KernelInfoState. For now this simply
3284d9659bf6SJohannes Doerfert /// forwards the information from the callee.
3285d9659bf6SJohannes Doerfert struct AAKernelInfoCallSite : AAKernelInfo {
3286d9659bf6SJohannes Doerfert   AAKernelInfoCallSite(const IRPosition &IRP, Attributor &A)
3287d9659bf6SJohannes Doerfert       : AAKernelInfo(IRP, A) {}
3288d9659bf6SJohannes Doerfert 
3289d9659bf6SJohannes Doerfert   /// See AbstractAttribute::initialize(...).
3290d9659bf6SJohannes Doerfert   void initialize(Attributor &A) override {
3291d9659bf6SJohannes Doerfert     AAKernelInfo::initialize(A);
3292d9659bf6SJohannes Doerfert 
3293d9659bf6SJohannes Doerfert     CallBase &CB = cast<CallBase>(getAssociatedValue());
3294d9659bf6SJohannes Doerfert     Function *Callee = getAssociatedFunction();
3295d9659bf6SJohannes Doerfert 
3296d9659bf6SJohannes Doerfert     // Helper to lookup an assumption string.
3297d9659bf6SJohannes Doerfert     auto HasAssumption = [](Function *Fn, StringRef AssumptionStr) {
3298d9659bf6SJohannes Doerfert       return Fn && hasAssumption(*Fn, AssumptionStr);
3299d9659bf6SJohannes Doerfert     };
3300d9659bf6SJohannes Doerfert 
3301514c033dSJohannes Doerfert     // Check for SPMD-mode assumptions.
3302514c033dSJohannes Doerfert     if (HasAssumption(Callee, "ompx_spmd_amenable"))
3303514c033dSJohannes Doerfert       SPMDCompatibilityTracker.indicateOptimisticFixpoint();
3304514c033dSJohannes Doerfert 
3305d9659bf6SJohannes Doerfert     // First weed out calls we do not care about, that is readonly/readnone
3306d9659bf6SJohannes Doerfert     // calls, intrinsics, and "no_openmp" calls. Neither of these can reach a
3307d9659bf6SJohannes Doerfert     // parallel region or anything else we are looking for.
3308d9659bf6SJohannes Doerfert     if (!CB.mayWriteToMemory() || isa<IntrinsicInst>(CB)) {
3309d9659bf6SJohannes Doerfert       indicateOptimisticFixpoint();
3310d9659bf6SJohannes Doerfert       return;
3311d9659bf6SJohannes Doerfert     }
3312d9659bf6SJohannes Doerfert 
3313d9659bf6SJohannes Doerfert     // Next we check if we know the callee. If it is a known OpenMP function
3314d9659bf6SJohannes Doerfert     // we will handle them explicitly in the switch below. If it is not, we
3315d9659bf6SJohannes Doerfert     // will use an AAKernelInfo object on the callee to gather information and
3316d9659bf6SJohannes Doerfert     // merge that into the current state. The latter happens in the updateImpl.
3317d9659bf6SJohannes Doerfert     auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
3318d9659bf6SJohannes Doerfert     const auto &It = OMPInfoCache.RuntimeFunctionIDMap.find(Callee);
3319d9659bf6SJohannes Doerfert     if (It == OMPInfoCache.RuntimeFunctionIDMap.end()) {
3320d9659bf6SJohannes Doerfert       // Unknown caller or declarations are not analyzable, we give up.
3321d9659bf6SJohannes Doerfert       if (!Callee || !A.isFunctionIPOAmendable(*Callee)) {
3322d9659bf6SJohannes Doerfert 
3323d9659bf6SJohannes Doerfert         // Unknown callees might contain parallel regions, except if they have
3324d9659bf6SJohannes Doerfert         // an appropriate assumption attached.
3325d9659bf6SJohannes Doerfert         if (!(HasAssumption(Callee, "omp_no_openmp") ||
3326d9659bf6SJohannes Doerfert               HasAssumption(Callee, "omp_no_parallelism")))
3327d9659bf6SJohannes Doerfert           ReachedUnknownParallelRegions.insert(&CB);
3328d9659bf6SJohannes Doerfert 
3329514c033dSJohannes Doerfert         // If SPMDCompatibilityTracker is not fixed, we need to give up on the
3330514c033dSJohannes Doerfert         // idea we can run something unknown in SPMD-mode.
3331514c033dSJohannes Doerfert         if (!SPMDCompatibilityTracker.isAtFixpoint())
3332514c033dSJohannes Doerfert           SPMDCompatibilityTracker.insert(&CB);
3333514c033dSJohannes Doerfert 
3334d9659bf6SJohannes Doerfert         // We have updated the state for this unknown call properly, there won't
3335d9659bf6SJohannes Doerfert         // be any change so we indicate a fixpoint.
3336d9659bf6SJohannes Doerfert         indicateOptimisticFixpoint();
3337d9659bf6SJohannes Doerfert       }
3338d9659bf6SJohannes Doerfert       // If the callee is known and can be used in IPO, we will update the state
3339d9659bf6SJohannes Doerfert       // based on the callee state in updateImpl.
3340d9659bf6SJohannes Doerfert       return;
3341d9659bf6SJohannes Doerfert     }
3342d9659bf6SJohannes Doerfert 
3343d9659bf6SJohannes Doerfert     const unsigned int WrapperFunctionArgNo = 6;
3344d9659bf6SJohannes Doerfert     RuntimeFunction RF = It->getSecond();
3345d9659bf6SJohannes Doerfert     switch (RF) {
3346514c033dSJohannes Doerfert     // All the functions we know are compatible with SPMD mode.
3347514c033dSJohannes Doerfert     case OMPRTL___kmpc_is_spmd_exec_mode:
3348514c033dSJohannes Doerfert     case OMPRTL___kmpc_for_static_fini:
3349514c033dSJohannes Doerfert     case OMPRTL___kmpc_global_thread_num:
3350514c033dSJohannes Doerfert     case OMPRTL___kmpc_single:
3351514c033dSJohannes Doerfert     case OMPRTL___kmpc_end_single:
3352514c033dSJohannes Doerfert     case OMPRTL___kmpc_master:
3353514c033dSJohannes Doerfert     case OMPRTL___kmpc_end_master:
3354514c033dSJohannes Doerfert     case OMPRTL___kmpc_barrier:
3355514c033dSJohannes Doerfert       break;
3356514c033dSJohannes Doerfert     case OMPRTL___kmpc_for_static_init_4:
3357514c033dSJohannes Doerfert     case OMPRTL___kmpc_for_static_init_4u:
3358514c033dSJohannes Doerfert     case OMPRTL___kmpc_for_static_init_8:
3359514c033dSJohannes Doerfert     case OMPRTL___kmpc_for_static_init_8u: {
3360514c033dSJohannes Doerfert       // Check the schedule and allow static schedule in SPMD mode.
3361514c033dSJohannes Doerfert       unsigned ScheduleArgOpNo = 2;
3362514c033dSJohannes Doerfert       auto *ScheduleTypeCI =
3363514c033dSJohannes Doerfert           dyn_cast<ConstantInt>(CB.getArgOperand(ScheduleArgOpNo));
3364514c033dSJohannes Doerfert       unsigned ScheduleTypeVal =
3365514c033dSJohannes Doerfert           ScheduleTypeCI ? ScheduleTypeCI->getZExtValue() : 0;
3366514c033dSJohannes Doerfert       switch (OMPScheduleType(ScheduleTypeVal)) {
3367514c033dSJohannes Doerfert       case OMPScheduleType::Static:
3368514c033dSJohannes Doerfert       case OMPScheduleType::StaticChunked:
3369514c033dSJohannes Doerfert       case OMPScheduleType::Distribute:
3370514c033dSJohannes Doerfert       case OMPScheduleType::DistributeChunked:
3371514c033dSJohannes Doerfert         break;
3372514c033dSJohannes Doerfert       default:
3373514c033dSJohannes Doerfert         SPMDCompatibilityTracker.insert(&CB);
3374514c033dSJohannes Doerfert         break;
3375514c033dSJohannes Doerfert       };
3376514c033dSJohannes Doerfert     } break;
3377d9659bf6SJohannes Doerfert     case OMPRTL___kmpc_target_init:
3378d9659bf6SJohannes Doerfert       KernelInitCB = &CB;
3379d9659bf6SJohannes Doerfert       break;
3380d9659bf6SJohannes Doerfert     case OMPRTL___kmpc_target_deinit:
3381d9659bf6SJohannes Doerfert       KernelDeinitCB = &CB;
3382d9659bf6SJohannes Doerfert       break;
3383d9659bf6SJohannes Doerfert     case OMPRTL___kmpc_parallel_51:
3384d9659bf6SJohannes Doerfert       if (auto *ParallelRegion = dyn_cast<Function>(
3385d9659bf6SJohannes Doerfert               CB.getArgOperand(WrapperFunctionArgNo)->stripPointerCasts())) {
3386d9659bf6SJohannes Doerfert         ReachedKnownParallelRegions.insert(ParallelRegion);
3387d9659bf6SJohannes Doerfert         break;
3388d9659bf6SJohannes Doerfert       }
3389d9659bf6SJohannes Doerfert       // The condition above should usually get the parallel region function
3390d9659bf6SJohannes Doerfert       // pointer and record it. In the off chance it doesn't we assume the
3391d9659bf6SJohannes Doerfert       // worst.
3392d9659bf6SJohannes Doerfert       ReachedUnknownParallelRegions.insert(&CB);
3393d9659bf6SJohannes Doerfert       break;
3394d9659bf6SJohannes Doerfert     case OMPRTL___kmpc_omp_task:
3395d9659bf6SJohannes Doerfert       // We do not look into tasks right now, just give up.
3396514c033dSJohannes Doerfert       SPMDCompatibilityTracker.insert(&CB);
3397d9659bf6SJohannes Doerfert       ReachedUnknownParallelRegions.insert(&CB);
3398d9659bf6SJohannes Doerfert       break;
3399d9659bf6SJohannes Doerfert     default:
3400514c033dSJohannes Doerfert       // Unknown OpenMP runtime calls cannot be executed in SPMD-mode,
3401514c033dSJohannes Doerfert       // generally.
3402514c033dSJohannes Doerfert       SPMDCompatibilityTracker.insert(&CB);
3403d9659bf6SJohannes Doerfert       break;
3404d9659bf6SJohannes Doerfert     }
3405d9659bf6SJohannes Doerfert     // All other OpenMP runtime calls will not reach parallel regions so they
3406d9659bf6SJohannes Doerfert     // can be safely ignored for now. Since it is a known OpenMP runtime call we
3407d9659bf6SJohannes Doerfert     // have now modeled all effects and there is no need for any update.
3408d9659bf6SJohannes Doerfert     indicateOptimisticFixpoint();
3409d9659bf6SJohannes Doerfert   }
3410d9659bf6SJohannes Doerfert 
3411d9659bf6SJohannes Doerfert   ChangeStatus updateImpl(Attributor &A) override {
3412d9659bf6SJohannes Doerfert     // TODO: Once we have call site specific value information we can provide
3413d9659bf6SJohannes Doerfert     //       call site specific liveness information and then it makes
3414d9659bf6SJohannes Doerfert     //       sense to specialize attributes for call sites arguments instead of
3415d9659bf6SJohannes Doerfert     //       redirecting requests to the callee argument.
3416d9659bf6SJohannes Doerfert     Function *F = getAssociatedFunction();
3417d9659bf6SJohannes Doerfert     const IRPosition &FnPos = IRPosition::function(*F);
3418d9659bf6SJohannes Doerfert     auto &FnAA = A.getAAFor<AAKernelInfo>(*this, FnPos, DepClassTy::REQUIRED);
3419d9659bf6SJohannes Doerfert     if (getState() == FnAA.getState())
3420d9659bf6SJohannes Doerfert       return ChangeStatus::UNCHANGED;
3421d9659bf6SJohannes Doerfert     getState() = FnAA.getState();
3422d9659bf6SJohannes Doerfert     return ChangeStatus::CHANGED;
3423d9659bf6SJohannes Doerfert   }
3424d9659bf6SJohannes Doerfert };
3425d9659bf6SJohannes Doerfert 
3426ca662297SShilei Tian struct AAFoldRuntimeCall
3427ca662297SShilei Tian     : public StateWrapper<BooleanState, AbstractAttribute> {
3428ca662297SShilei Tian   using Base = StateWrapper<BooleanState, AbstractAttribute>;
3429ca662297SShilei Tian 
3430ca662297SShilei Tian   AAFoldRuntimeCall(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
3431ca662297SShilei Tian 
3432ca662297SShilei Tian   /// Statistics are tracked as part of manifest for now.
3433ca662297SShilei Tian   void trackStatistics() const override {}
3434ca662297SShilei Tian 
3435ca662297SShilei Tian   /// Create an abstract attribute biew for the position \p IRP.
3436ca662297SShilei Tian   static AAFoldRuntimeCall &createForPosition(const IRPosition &IRP,
3437ca662297SShilei Tian                                               Attributor &A);
3438ca662297SShilei Tian 
3439ca662297SShilei Tian   /// See AbstractAttribute::getName()
3440ca662297SShilei Tian   const std::string getName() const override { return "AAFoldRuntimeCall"; }
3441ca662297SShilei Tian 
3442ca662297SShilei Tian   /// See AbstractAttribute::getIdAddr()
3443ca662297SShilei Tian   const char *getIdAddr() const override { return &ID; }
3444ca662297SShilei Tian 
3445ca662297SShilei Tian   /// This function should return true if the type of the \p AA is
3446ca662297SShilei Tian   /// AAFoldRuntimeCall
3447ca662297SShilei Tian   static bool classof(const AbstractAttribute *AA) {
3448ca662297SShilei Tian     return (AA->getIdAddr() == &ID);
3449ca662297SShilei Tian   }
3450ca662297SShilei Tian 
3451ca662297SShilei Tian   static const char ID;
3452ca662297SShilei Tian };
3453ca662297SShilei Tian 
3454ca662297SShilei Tian struct AAFoldRuntimeCallCallSiteReturned : AAFoldRuntimeCall {
3455ca662297SShilei Tian   AAFoldRuntimeCallCallSiteReturned(const IRPosition &IRP, Attributor &A)
3456ca662297SShilei Tian       : AAFoldRuntimeCall(IRP, A) {}
3457ca662297SShilei Tian 
3458ca662297SShilei Tian   /// See AbstractAttribute::getAsStr()
3459ca662297SShilei Tian   const std::string getAsStr() const override {
3460ca662297SShilei Tian     if (!isValidState())
3461ca662297SShilei Tian       return "<invalid>";
3462ca662297SShilei Tian 
3463ca662297SShilei Tian     std::string Str("simplified value: ");
3464ca662297SShilei Tian 
3465ca662297SShilei Tian     if (!SimplifiedValue.hasValue())
3466ca662297SShilei Tian       return Str + std::string("none");
3467ca662297SShilei Tian 
3468ca662297SShilei Tian     if (!SimplifiedValue.getValue())
3469ca662297SShilei Tian       return Str + std::string("nullptr");
3470ca662297SShilei Tian 
3471ca662297SShilei Tian     if (ConstantInt *CI = dyn_cast<ConstantInt>(SimplifiedValue.getValue()))
3472ca662297SShilei Tian       return Str + std::to_string(CI->getSExtValue());
3473ca662297SShilei Tian 
3474ca662297SShilei Tian     return Str + std::string("unknown");
3475ca662297SShilei Tian   }
3476ca662297SShilei Tian 
3477ca662297SShilei Tian   void initialize(Attributor &A) override {
3478ca662297SShilei Tian     Function *Callee = getAssociatedFunction();
3479ca662297SShilei Tian 
3480ca662297SShilei Tian     auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
3481ca662297SShilei Tian     const auto &It = OMPInfoCache.RuntimeFunctionIDMap.find(Callee);
3482ca662297SShilei Tian     assert(It != OMPInfoCache.RuntimeFunctionIDMap.end() &&
3483ca662297SShilei Tian            "Expected a known OpenMP runtime function");
3484ca662297SShilei Tian 
3485ca662297SShilei Tian     RFKind = It->getSecond();
3486ca662297SShilei Tian 
3487ca662297SShilei Tian     CallBase &CB = cast<CallBase>(getAssociatedValue());
3488ca662297SShilei Tian     A.registerSimplificationCallback(
3489ca662297SShilei Tian         IRPosition::callsite_returned(CB),
3490ca662297SShilei Tian         [&](const IRPosition &IRP, const AbstractAttribute *AA,
3491ca662297SShilei Tian             bool &UsedAssumedInformation) -> Optional<Value *> {
3492ca662297SShilei Tian           assert((isValidState() || (SimplifiedValue.hasValue() &&
3493ca662297SShilei Tian                                      SimplifiedValue.getValue() == nullptr)) &&
3494ca662297SShilei Tian                  "Unexpected invalid state!");
3495ca662297SShilei Tian 
3496ca662297SShilei Tian           if (!isAtFixpoint()) {
3497ca662297SShilei Tian             UsedAssumedInformation = true;
3498ca662297SShilei Tian             if (AA)
3499ca662297SShilei Tian               A.recordDependence(*this, *AA, DepClassTy::OPTIONAL);
3500ca662297SShilei Tian           }
3501ca662297SShilei Tian           return SimplifiedValue;
3502ca662297SShilei Tian         });
3503ca662297SShilei Tian   }
3504ca662297SShilei Tian 
3505ca662297SShilei Tian   ChangeStatus updateImpl(Attributor &A) override {
3506ca662297SShilei Tian     ChangeStatus Changed = ChangeStatus::UNCHANGED;
3507ca662297SShilei Tian 
3508ca662297SShilei Tian     switch (RFKind) {
3509ca662297SShilei Tian     case OMPRTL___kmpc_is_spmd_exec_mode:
3510c23da666SShilei Tian       Changed |= foldIsSPMDExecMode(A);
3511ca662297SShilei Tian       break;
3512ca662297SShilei Tian     default:
3513ca662297SShilei Tian       llvm_unreachable("Unhandled OpenMP runtime function!");
3514ca662297SShilei Tian     }
3515ca662297SShilei Tian 
3516ca662297SShilei Tian     return Changed;
3517ca662297SShilei Tian   }
3518ca662297SShilei Tian 
3519ca662297SShilei Tian   ChangeStatus manifest(Attributor &A) override {
3520ca662297SShilei Tian     ChangeStatus Changed = ChangeStatus::UNCHANGED;
3521ca662297SShilei Tian 
3522ca662297SShilei Tian     if (SimplifiedValue.hasValue() && SimplifiedValue.getValue()) {
3523ca662297SShilei Tian       Instruction &CB = *getCtxI();
3524ca662297SShilei Tian       A.changeValueAfterManifest(CB, **SimplifiedValue);
3525ca662297SShilei Tian       A.deleteAfterManifest(CB);
3526ca662297SShilei Tian       Changed = ChangeStatus::CHANGED;
3527ca662297SShilei Tian     }
3528ca662297SShilei Tian 
3529ca662297SShilei Tian     return Changed;
3530ca662297SShilei Tian   }
3531ca662297SShilei Tian 
3532ca662297SShilei Tian   ChangeStatus indicatePessimisticFixpoint() override {
3533ca662297SShilei Tian     SimplifiedValue = nullptr;
3534ca662297SShilei Tian     return AAFoldRuntimeCall::indicatePessimisticFixpoint();
3535ca662297SShilei Tian   }
3536ca662297SShilei Tian 
3537ca662297SShilei Tian private:
3538ca662297SShilei Tian   /// Fold __kmpc_is_spmd_exec_mode into a constant if possible.
3539ca662297SShilei Tian   ChangeStatus foldIsSPMDExecMode(Attributor &A) {
3540ca662297SShilei Tian     Optional<Value *> SimplifiedValueBefore = SimplifiedValue;
3541ca662297SShilei Tian 
3542ca662297SShilei Tian     unsigned AssumedSPMDCount = 0, KnownSPMDCount = 0;
3543ca662297SShilei Tian     unsigned AssumedNonSPMDCount = 0, KnownNonSPMDCount = 0;
3544ca662297SShilei Tian     auto &CallerKernelInfoAA = A.getAAFor<AAKernelInfo>(
3545ca662297SShilei Tian         *this, IRPosition::function(*getAnchorScope()), DepClassTy::REQUIRED);
3546ca662297SShilei Tian 
3547ca662297SShilei Tian     if (!CallerKernelInfoAA.ReachingKernelEntries.isValidState())
3548ca662297SShilei Tian       return indicatePessimisticFixpoint();
3549ca662297SShilei Tian 
3550ca662297SShilei Tian     for (Kernel K : CallerKernelInfoAA.ReachingKernelEntries) {
3551ca662297SShilei Tian       auto &AA = A.getAAFor<AAKernelInfo>(*this, IRPosition::function(*K),
3552ca662297SShilei Tian                                           DepClassTy::REQUIRED);
3553ca662297SShilei Tian 
3554ca662297SShilei Tian       if (!AA.isValidState()) {
3555ca662297SShilei Tian         SimplifiedValue = nullptr;
3556ca662297SShilei Tian         return indicatePessimisticFixpoint();
3557ca662297SShilei Tian       }
3558ca662297SShilei Tian 
3559ca662297SShilei Tian       if (AA.SPMDCompatibilityTracker.isAssumed()) {
3560ca662297SShilei Tian         if (AA.SPMDCompatibilityTracker.isAtFixpoint())
3561ca662297SShilei Tian           ++KnownSPMDCount;
3562ca662297SShilei Tian         else
3563ca662297SShilei Tian           ++AssumedSPMDCount;
3564ca662297SShilei Tian       } else {
3565ca662297SShilei Tian         if (AA.SPMDCompatibilityTracker.isAtFixpoint())
3566ca662297SShilei Tian           ++KnownNonSPMDCount;
3567ca662297SShilei Tian         else
3568ca662297SShilei Tian           ++AssumedNonSPMDCount;
3569ca662297SShilei Tian       }
3570ca662297SShilei Tian     }
3571ca662297SShilei Tian 
3572ca662297SShilei Tian     if (KnownSPMDCount && KnownNonSPMDCount)
3573ca662297SShilei Tian       return indicatePessimisticFixpoint();
3574ca662297SShilei Tian 
3575ca662297SShilei Tian     if (AssumedSPMDCount && AssumedNonSPMDCount)
3576ca662297SShilei Tian       return indicatePessimisticFixpoint();
3577ca662297SShilei Tian 
3578ca662297SShilei Tian     auto &Ctx = getAnchorValue().getContext();
3579ca662297SShilei Tian     if (KnownSPMDCount || AssumedSPMDCount) {
3580ca662297SShilei Tian       assert(KnownNonSPMDCount == 0 && AssumedNonSPMDCount == 0 &&
3581ca662297SShilei Tian              "Expected only SPMD kernels!");
3582ca662297SShilei Tian       // All reaching kernels are in SPMD mode. Update all function calls to
3583ca662297SShilei Tian       // __kmpc_is_spmd_exec_mode to 1.
3584ca662297SShilei Tian       SimplifiedValue = ConstantInt::get(Type::getInt8Ty(Ctx), true);
3585d3454ee8SShilei Tian     } else if (KnownNonSPMDCount || AssumedNonSPMDCount) {
3586ca662297SShilei Tian       assert(KnownSPMDCount == 0 && AssumedSPMDCount == 0 &&
3587ca662297SShilei Tian              "Expected only non-SPMD kernels!");
3588ca662297SShilei Tian       // All reaching kernels are in non-SPMD mode. Update all function
3589ca662297SShilei Tian       // calls to __kmpc_is_spmd_exec_mode to 0.
3590ca662297SShilei Tian       SimplifiedValue = ConstantInt::get(Type::getInt8Ty(Ctx), false);
3591d3454ee8SShilei Tian     } else {
3592d3454ee8SShilei Tian       // We have empty reaching kernels, therefore we cannot tell if the
3593d3454ee8SShilei Tian       // associated call site can be folded. At this moment, SimplifiedValue
3594d3454ee8SShilei Tian       // must be none.
3595d3454ee8SShilei Tian       assert(!SimplifiedValue.hasValue() && "SimplifiedValue should be none");
3596ca662297SShilei Tian     }
3597ca662297SShilei Tian 
3598ca662297SShilei Tian     return SimplifiedValue == SimplifiedValueBefore ? ChangeStatus::UNCHANGED
3599ca662297SShilei Tian                                                     : ChangeStatus::CHANGED;
3600ca662297SShilei Tian   }
3601ca662297SShilei Tian 
3602ca662297SShilei Tian   /// An optional value the associated value is assumed to fold to. That is, we
3603ca662297SShilei Tian   /// assume the associated value (which is a call) can be replaced by this
3604ca662297SShilei Tian   /// simplified value.
3605ca662297SShilei Tian   Optional<Value *> SimplifiedValue;
3606ca662297SShilei Tian 
3607ca662297SShilei Tian   /// The runtime function kind of the callee of the associated call site.
3608ca662297SShilei Tian   RuntimeFunction RFKind;
3609ca662297SShilei Tian };
3610ca662297SShilei Tian 
36119548b74aSJohannes Doerfert } // namespace
36129548b74aSJohannes Doerfert 
3613d9659bf6SJohannes Doerfert void OpenMPOpt::registerAAs(bool IsModulePass) {
3614d9659bf6SJohannes Doerfert   if (SCC.empty())
3615d9659bf6SJohannes Doerfert 
3616d9659bf6SJohannes Doerfert     return;
3617d9659bf6SJohannes Doerfert   if (IsModulePass) {
3618d9659bf6SJohannes Doerfert     // Ensure we create the AAKernelInfo AAs first and without triggering an
3619d9659bf6SJohannes Doerfert     // update. This will make sure we register all value simplification
3620d9659bf6SJohannes Doerfert     // callbacks before any other AA has the chance to create an AAValueSimplify
3621d9659bf6SJohannes Doerfert     // or similar.
3622d9659bf6SJohannes Doerfert     for (Function *Kernel : OMPInfoCache.Kernels)
3623d9659bf6SJohannes Doerfert       A.getOrCreateAAFor<AAKernelInfo>(
3624d9659bf6SJohannes Doerfert           IRPosition::function(*Kernel), /* QueryingAA */ nullptr,
3625d9659bf6SJohannes Doerfert           DepClassTy::NONE, /* ForceUpdate */ false,
3626d9659bf6SJohannes Doerfert           /* UpdateAfterInit */ false);
3627ca662297SShilei Tian 
3628ca662297SShilei Tian     auto &IsSPMDRFI = OMPInfoCache.RFIs[OMPRTL___kmpc_is_spmd_exec_mode];
3629ca662297SShilei Tian     IsSPMDRFI.foreachUse(SCC, [&](Use &U, Function &) {
3630ca662297SShilei Tian       CallInst *CI = OpenMPOpt::getCallIfRegularCall(U, &IsSPMDRFI);
3631ca662297SShilei Tian       if (!CI)
3632ca662297SShilei Tian         return false;
3633ca662297SShilei Tian       A.getOrCreateAAFor<AAFoldRuntimeCall>(
3634ca662297SShilei Tian           IRPosition::callsite_returned(*CI), /* QueryingAA */ nullptr,
3635ca662297SShilei Tian           DepClassTy::NONE, /* ForceUpdate */ false,
3636ca662297SShilei Tian           /* UpdateAfterInit */ false);
3637ca662297SShilei Tian       return false;
3638ca662297SShilei Tian     });
3639d9659bf6SJohannes Doerfert   }
3640d9659bf6SJohannes Doerfert 
3641d9659bf6SJohannes Doerfert   // Create CallSite AA for all Getters.
3642d9659bf6SJohannes Doerfert   for (int Idx = 0; Idx < OMPInfoCache.ICVs.size() - 1; ++Idx) {
3643d9659bf6SJohannes Doerfert     auto ICVInfo = OMPInfoCache.ICVs[static_cast<InternalControlVar>(Idx)];
3644d9659bf6SJohannes Doerfert 
3645d9659bf6SJohannes Doerfert     auto &GetterRFI = OMPInfoCache.RFIs[ICVInfo.Getter];
3646d9659bf6SJohannes Doerfert 
3647d9659bf6SJohannes Doerfert     auto CreateAA = [&](Use &U, Function &Caller) {
3648d9659bf6SJohannes Doerfert       CallInst *CI = OpenMPOpt::getCallIfRegularCall(U, &GetterRFI);
3649d9659bf6SJohannes Doerfert       if (!CI)
3650d9659bf6SJohannes Doerfert         return false;
3651d9659bf6SJohannes Doerfert 
3652d9659bf6SJohannes Doerfert       auto &CB = cast<CallBase>(*CI);
3653d9659bf6SJohannes Doerfert 
3654d9659bf6SJohannes Doerfert       IRPosition CBPos = IRPosition::callsite_function(CB);
3655d9659bf6SJohannes Doerfert       A.getOrCreateAAFor<AAICVTracker>(CBPos);
3656d9659bf6SJohannes Doerfert       return false;
3657d9659bf6SJohannes Doerfert     };
3658d9659bf6SJohannes Doerfert 
3659d9659bf6SJohannes Doerfert     GetterRFI.foreachUse(SCC, CreateAA);
3660d9659bf6SJohannes Doerfert   }
3661d9659bf6SJohannes Doerfert   auto &GlobalizationRFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
3662d9659bf6SJohannes Doerfert   auto CreateAA = [&](Use &U, Function &F) {
3663d9659bf6SJohannes Doerfert     A.getOrCreateAAFor<AAHeapToShared>(IRPosition::function(F));
3664d9659bf6SJohannes Doerfert     return false;
3665d9659bf6SJohannes Doerfert   };
3666d9659bf6SJohannes Doerfert   GlobalizationRFI.foreachUse(SCC, CreateAA);
3667d9659bf6SJohannes Doerfert 
3668d9659bf6SJohannes Doerfert   // Create an ExecutionDomain AA for every function and a HeapToStack AA for
3669d9659bf6SJohannes Doerfert   // every function if there is a device kernel.
3670d9659bf6SJohannes Doerfert   for (auto *F : SCC) {
3671d9659bf6SJohannes Doerfert     if (!F->isDeclaration())
3672d9659bf6SJohannes Doerfert       A.getOrCreateAAFor<AAExecutionDomain>(IRPosition::function(*F));
3673d9659bf6SJohannes Doerfert     if (isOpenMPDevice(M))
3674d9659bf6SJohannes Doerfert       A.getOrCreateAAFor<AAHeapToStack>(IRPosition::function(*F));
3675d9659bf6SJohannes Doerfert   }
3676d9659bf6SJohannes Doerfert }
3677d9659bf6SJohannes Doerfert 
3678b8235d2bSsstefan1 const char AAICVTracker::ID = 0;
3679d9659bf6SJohannes Doerfert const char AAKernelInfo::ID = 0;
368018283125SJoseph Huber const char AAExecutionDomain::ID = 0;
36816fc51c9fSJoseph Huber const char AAHeapToShared::ID = 0;
3682ca662297SShilei Tian const char AAFoldRuntimeCall::ID = 0;
3683b8235d2bSsstefan1 
3684b8235d2bSsstefan1 AAICVTracker &AAICVTracker::createForPosition(const IRPosition &IRP,
3685b8235d2bSsstefan1                                               Attributor &A) {
3686b8235d2bSsstefan1   AAICVTracker *AA = nullptr;
3687b8235d2bSsstefan1   switch (IRP.getPositionKind()) {
3688b8235d2bSsstefan1   case IRPosition::IRP_INVALID:
3689b8235d2bSsstefan1   case IRPosition::IRP_FLOAT:
3690b8235d2bSsstefan1   case IRPosition::IRP_ARGUMENT:
3691b8235d2bSsstefan1   case IRPosition::IRP_CALL_SITE_ARGUMENT:
36921de70a72SJohannes Doerfert     llvm_unreachable("ICVTracker can only be created for function position!");
36935dfd7cc4Ssstefan1   case IRPosition::IRP_RETURNED:
36945dfd7cc4Ssstefan1     AA = new (A.Allocator) AAICVTrackerFunctionReturned(IRP, A);
36955dfd7cc4Ssstefan1     break;
36965dfd7cc4Ssstefan1   case IRPosition::IRP_CALL_SITE_RETURNED:
36975dfd7cc4Ssstefan1     AA = new (A.Allocator) AAICVTrackerCallSiteReturned(IRP, A);
36985dfd7cc4Ssstefan1     break;
36995dfd7cc4Ssstefan1   case IRPosition::IRP_CALL_SITE:
37005dfd7cc4Ssstefan1     AA = new (A.Allocator) AAICVTrackerCallSite(IRP, A);
37015dfd7cc4Ssstefan1     break;
3702b8235d2bSsstefan1   case IRPosition::IRP_FUNCTION:
3703b8235d2bSsstefan1     AA = new (A.Allocator) AAICVTrackerFunction(IRP, A);
3704b8235d2bSsstefan1     break;
3705b8235d2bSsstefan1   }
3706b8235d2bSsstefan1 
3707b8235d2bSsstefan1   return *AA;
3708b8235d2bSsstefan1 }
3709b8235d2bSsstefan1 
371018283125SJoseph Huber AAExecutionDomain &AAExecutionDomain::createForPosition(const IRPosition &IRP,
371118283125SJoseph Huber                                                         Attributor &A) {
371218283125SJoseph Huber   AAExecutionDomainFunction *AA = nullptr;
371318283125SJoseph Huber   switch (IRP.getPositionKind()) {
371418283125SJoseph Huber   case IRPosition::IRP_INVALID:
371518283125SJoseph Huber   case IRPosition::IRP_FLOAT:
371618283125SJoseph Huber   case IRPosition::IRP_ARGUMENT:
371718283125SJoseph Huber   case IRPosition::IRP_CALL_SITE_ARGUMENT:
371818283125SJoseph Huber   case IRPosition::IRP_RETURNED:
371918283125SJoseph Huber   case IRPosition::IRP_CALL_SITE_RETURNED:
372018283125SJoseph Huber   case IRPosition::IRP_CALL_SITE:
372118283125SJoseph Huber     llvm_unreachable(
372218283125SJoseph Huber         "AAExecutionDomain can only be created for function position!");
372318283125SJoseph Huber   case IRPosition::IRP_FUNCTION:
372418283125SJoseph Huber     AA = new (A.Allocator) AAExecutionDomainFunction(IRP, A);
372518283125SJoseph Huber     break;
372618283125SJoseph Huber   }
372718283125SJoseph Huber 
372818283125SJoseph Huber   return *AA;
372918283125SJoseph Huber }
373018283125SJoseph Huber 
37316fc51c9fSJoseph Huber AAHeapToShared &AAHeapToShared::createForPosition(const IRPosition &IRP,
37326fc51c9fSJoseph Huber                                                   Attributor &A) {
37336fc51c9fSJoseph Huber   AAHeapToSharedFunction *AA = nullptr;
37346fc51c9fSJoseph Huber   switch (IRP.getPositionKind()) {
37356fc51c9fSJoseph Huber   case IRPosition::IRP_INVALID:
37366fc51c9fSJoseph Huber   case IRPosition::IRP_FLOAT:
37376fc51c9fSJoseph Huber   case IRPosition::IRP_ARGUMENT:
37386fc51c9fSJoseph Huber   case IRPosition::IRP_CALL_SITE_ARGUMENT:
37396fc51c9fSJoseph Huber   case IRPosition::IRP_RETURNED:
37406fc51c9fSJoseph Huber   case IRPosition::IRP_CALL_SITE_RETURNED:
37416fc51c9fSJoseph Huber   case IRPosition::IRP_CALL_SITE:
37426fc51c9fSJoseph Huber     llvm_unreachable(
37436fc51c9fSJoseph Huber         "AAHeapToShared can only be created for function position!");
37446fc51c9fSJoseph Huber   case IRPosition::IRP_FUNCTION:
37456fc51c9fSJoseph Huber     AA = new (A.Allocator) AAHeapToSharedFunction(IRP, A);
37466fc51c9fSJoseph Huber     break;
37476fc51c9fSJoseph Huber   }
37486fc51c9fSJoseph Huber 
37496fc51c9fSJoseph Huber   return *AA;
37506fc51c9fSJoseph Huber }
37516fc51c9fSJoseph Huber 
3752d9659bf6SJohannes Doerfert AAKernelInfo &AAKernelInfo::createForPosition(const IRPosition &IRP,
3753d9659bf6SJohannes Doerfert                                               Attributor &A) {
3754d9659bf6SJohannes Doerfert   AAKernelInfo *AA = nullptr;
3755d9659bf6SJohannes Doerfert   switch (IRP.getPositionKind()) {
3756d9659bf6SJohannes Doerfert   case IRPosition::IRP_INVALID:
3757d9659bf6SJohannes Doerfert   case IRPosition::IRP_FLOAT:
3758d9659bf6SJohannes Doerfert   case IRPosition::IRP_ARGUMENT:
3759d9659bf6SJohannes Doerfert   case IRPosition::IRP_RETURNED:
3760d9659bf6SJohannes Doerfert   case IRPosition::IRP_CALL_SITE_RETURNED:
3761d9659bf6SJohannes Doerfert   case IRPosition::IRP_CALL_SITE_ARGUMENT:
3762d9659bf6SJohannes Doerfert     llvm_unreachable("KernelInfo can only be created for function position!");
3763d9659bf6SJohannes Doerfert   case IRPosition::IRP_CALL_SITE:
3764d9659bf6SJohannes Doerfert     AA = new (A.Allocator) AAKernelInfoCallSite(IRP, A);
3765d9659bf6SJohannes Doerfert     break;
3766d9659bf6SJohannes Doerfert   case IRPosition::IRP_FUNCTION:
3767d9659bf6SJohannes Doerfert     AA = new (A.Allocator) AAKernelInfoFunction(IRP, A);
3768d9659bf6SJohannes Doerfert     break;
3769d9659bf6SJohannes Doerfert   }
3770d9659bf6SJohannes Doerfert 
3771d9659bf6SJohannes Doerfert   return *AA;
3772d9659bf6SJohannes Doerfert }
3773d9659bf6SJohannes Doerfert 
3774ca662297SShilei Tian AAFoldRuntimeCall &AAFoldRuntimeCall::createForPosition(const IRPosition &IRP,
3775ca662297SShilei Tian                                                         Attributor &A) {
3776ca662297SShilei Tian   AAFoldRuntimeCall *AA = nullptr;
3777ca662297SShilei Tian   switch (IRP.getPositionKind()) {
3778ca662297SShilei Tian   case IRPosition::IRP_INVALID:
3779ca662297SShilei Tian   case IRPosition::IRP_FLOAT:
3780ca662297SShilei Tian   case IRPosition::IRP_ARGUMENT:
3781ca662297SShilei Tian   case IRPosition::IRP_RETURNED:
3782ca662297SShilei Tian   case IRPosition::IRP_FUNCTION:
3783ca662297SShilei Tian   case IRPosition::IRP_CALL_SITE:
3784ca662297SShilei Tian   case IRPosition::IRP_CALL_SITE_ARGUMENT:
3785ca662297SShilei Tian     llvm_unreachable("KernelInfo can only be created for call site position!");
3786ca662297SShilei Tian   case IRPosition::IRP_CALL_SITE_RETURNED:
3787ca662297SShilei Tian     AA = new (A.Allocator) AAFoldRuntimeCallCallSiteReturned(IRP, A);
3788ca662297SShilei Tian     break;
3789ca662297SShilei Tian   }
3790ca662297SShilei Tian 
3791ca662297SShilei Tian   return *AA;
3792ca662297SShilei Tian }
3793ca662297SShilei Tian 
3794b2ad63d3SJoseph Huber PreservedAnalyses OpenMPOptPass::run(Module &M, ModuleAnalysisManager &AM) {
37955ccb7424SJoseph Huber   if (!containsOpenMP(M))
3796b2ad63d3SJoseph Huber     return PreservedAnalyses::all();
3797b2ad63d3SJoseph Huber   if (DisableOpenMPOptimizations)
3798b2ad63d3SJoseph Huber     return PreservedAnalyses::all();
3799b2ad63d3SJoseph Huber 
38000edb8777SJoseph Huber   FunctionAnalysisManager &FAM =
38010edb8777SJoseph Huber       AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
38025ccb7424SJoseph Huber   KernelSet Kernels = getDeviceKernels(M);
38035ccb7424SJoseph Huber 
380457ad2e10SJoseph Huber   auto IsCalled = [&](Function &F) {
380557ad2e10SJoseph Huber     if (Kernels.contains(&F))
380657ad2e10SJoseph Huber       return true;
380757ad2e10SJoseph Huber     for (const User *U : F.users())
380857ad2e10SJoseph Huber       if (!isa<BlockAddress>(U))
380957ad2e10SJoseph Huber         return true;
381057ad2e10SJoseph Huber     return false;
381157ad2e10SJoseph Huber   };
381257ad2e10SJoseph Huber 
38130edb8777SJoseph Huber   auto EmitRemark = [&](Function &F) {
38140edb8777SJoseph Huber     auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);
38150edb8777SJoseph Huber     ORE.emit([&]() {
38162c31d5ebSJoseph Huber       OptimizationRemarkAnalysis ORA(DEBUG_TYPE, "OMP140", &F);
3817ecabc668SJoseph Huber       return ORA << "Could not internalize function. "
38180edb8777SJoseph Huber                  << "Some optimizations may not be possible.";
38190edb8777SJoseph Huber     });
38200edb8777SJoseph Huber   };
38210edb8777SJoseph Huber 
382257ad2e10SJoseph Huber   // Create internal copies of each function if this is a kernel Module. This
382357ad2e10SJoseph Huber   // allows iterprocedural passes to see every call edge.
382403d7e61cSJoseph Huber   DenseSet<const Function *> InternalizedFuncs;
38255ccb7424SJoseph Huber   if (isOpenMPDevice(M))
382603d7e61cSJoseph Huber     for (Function &F : M)
38270edb8777SJoseph Huber       if (!F.isDeclaration() && !Kernels.contains(&F) && IsCalled(F)) {
38280edb8777SJoseph Huber         if (Attributor::internalizeFunction(F, /* Force */ true)) {
382903d7e61cSJoseph Huber           InternalizedFuncs.insert(&F);
3830ecabc668SJoseph Huber         } else if (!F.hasLocalLinkage() && !F.hasFnAttribute(Attribute::Cold)) {
38310edb8777SJoseph Huber           EmitRemark(F);
38320edb8777SJoseph Huber         }
38330edb8777SJoseph Huber       }
383403d7e61cSJoseph Huber 
383557ad2e10SJoseph Huber   // Look at every function in the Module unless it was internalized.
3836b2ad63d3SJoseph Huber   SmallVector<Function *, 16> SCC;
383703d7e61cSJoseph Huber   for (Function &F : M)
383803d7e61cSJoseph Huber     if (!F.isDeclaration() && !InternalizedFuncs.contains(&F))
383903d7e61cSJoseph Huber       SCC.push_back(&F);
3840b2ad63d3SJoseph Huber 
3841b2ad63d3SJoseph Huber   if (SCC.empty())
3842b2ad63d3SJoseph Huber     return PreservedAnalyses::all();
3843b2ad63d3SJoseph Huber 
3844b2ad63d3SJoseph Huber   AnalysisGetter AG(FAM);
3845b2ad63d3SJoseph Huber 
3846b2ad63d3SJoseph Huber   auto OREGetter = [&FAM](Function *F) -> OptimizationRemarkEmitter & {
3847b2ad63d3SJoseph Huber     return FAM.getResult<OptimizationRemarkEmitterAnalysis>(*F);
3848b2ad63d3SJoseph Huber   };
3849b2ad63d3SJoseph Huber 
3850b2ad63d3SJoseph Huber   BumpPtrAllocator Allocator;
3851b2ad63d3SJoseph Huber   CallGraphUpdater CGUpdater;
3852b2ad63d3SJoseph Huber 
3853b2ad63d3SJoseph Huber   SetVector<Function *> Functions(SCC.begin(), SCC.end());
38545ccb7424SJoseph Huber   OMPInformationCache InfoCache(M, AG, Allocator, /*CGSCC*/ Functions, Kernels);
3855b2ad63d3SJoseph Huber 
385613b2fba2SJoseph Huber   unsigned MaxFixpointIterations = (isOpenMPDevice(M)) ? 128 : 32;
38574a6bd8e3SJoseph Huber   Attributor A(Functions, InfoCache, CGUpdater, nullptr, true, false,
385813b2fba2SJoseph Huber                MaxFixpointIterations, OREGetter, DEBUG_TYPE);
3859b2ad63d3SJoseph Huber 
3860b2ad63d3SJoseph Huber   OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache, A);
3861b2ad63d3SJoseph Huber   bool Changed = OMPOpt.run(true);
3862b2ad63d3SJoseph Huber   if (Changed)
3863b2ad63d3SJoseph Huber     return PreservedAnalyses::none();
3864b2ad63d3SJoseph Huber 
3865b2ad63d3SJoseph Huber   return PreservedAnalyses::all();
3866b2ad63d3SJoseph Huber }
3867b2ad63d3SJoseph Huber 
3868b2ad63d3SJoseph Huber PreservedAnalyses OpenMPOptCGSCCPass::run(LazyCallGraph::SCC &C,
38699548b74aSJohannes Doerfert                                           CGSCCAnalysisManager &AM,
3870b2ad63d3SJoseph Huber                                           LazyCallGraph &CG,
3871b2ad63d3SJoseph Huber                                           CGSCCUpdateResult &UR) {
38725ccb7424SJoseph Huber   if (!containsOpenMP(*C.begin()->getFunction().getParent()))
38739548b74aSJohannes Doerfert     return PreservedAnalyses::all();
38749548b74aSJohannes Doerfert   if (DisableOpenMPOptimizations)
38759548b74aSJohannes Doerfert     return PreservedAnalyses::all();
38769548b74aSJohannes Doerfert 
3877ee17263aSJohannes Doerfert   SmallVector<Function *, 16> SCC;
3878351d234dSRoman Lebedev   // If there are kernels in the module, we have to run on all SCC's.
3879351d234dSRoman Lebedev   for (LazyCallGraph::Node &N : C) {
3880351d234dSRoman Lebedev     Function *Fn = &N.getFunction();
3881351d234dSRoman Lebedev     SCC.push_back(Fn);
3882351d234dSRoman Lebedev   }
3883351d234dSRoman Lebedev 
38845ccb7424SJoseph Huber   if (SCC.empty())
38859548b74aSJohannes Doerfert     return PreservedAnalyses::all();
38869548b74aSJohannes Doerfert 
38875ccb7424SJoseph Huber   Module &M = *C.begin()->getFunction().getParent();
38885ccb7424SJoseph Huber 
38895ccb7424SJoseph Huber   KernelSet Kernels = getDeviceKernels(M);
38905ccb7424SJoseph Huber 
38914d4ea9acSHuber, Joseph   FunctionAnalysisManager &FAM =
38924d4ea9acSHuber, Joseph       AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
38937cfd267cSsstefan1 
38947cfd267cSsstefan1   AnalysisGetter AG(FAM);
38957cfd267cSsstefan1 
38967cfd267cSsstefan1   auto OREGetter = [&FAM](Function *F) -> OptimizationRemarkEmitter & {
38974d4ea9acSHuber, Joseph     return FAM.getResult<OptimizationRemarkEmitterAnalysis>(*F);
38984d4ea9acSHuber, Joseph   };
38994d4ea9acSHuber, Joseph 
3900b2ad63d3SJoseph Huber   BumpPtrAllocator Allocator;
39019548b74aSJohannes Doerfert   CallGraphUpdater CGUpdater;
39029548b74aSJohannes Doerfert   CGUpdater.initialize(CG, C, AM, UR);
39037cfd267cSsstefan1 
39047cfd267cSsstefan1   SetVector<Function *> Functions(SCC.begin(), SCC.end());
39057cfd267cSsstefan1   OMPInformationCache InfoCache(*(Functions.back()->getParent()), AG, Allocator,
39065ccb7424SJoseph Huber                                 /*CGSCC*/ Functions, Kernels);
39077cfd267cSsstefan1 
390813b2fba2SJoseph Huber   unsigned MaxFixpointIterations = (isOpenMPDevice(M)) ? 128 : 32;
39094a6bd8e3SJoseph Huber   Attributor A(Functions, InfoCache, CGUpdater, nullptr, false, true,
391013b2fba2SJoseph Huber                MaxFixpointIterations, OREGetter, DEBUG_TYPE);
3911b8235d2bSsstefan1 
3912b8235d2bSsstefan1   OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache, A);
3913b2ad63d3SJoseph Huber   bool Changed = OMPOpt.run(false);
3914694ded37SGiorgis Georgakoudis   if (Changed)
3915694ded37SGiorgis Georgakoudis     return PreservedAnalyses::none();
3916694ded37SGiorgis Georgakoudis 
39179548b74aSJohannes Doerfert   return PreservedAnalyses::all();
39189548b74aSJohannes Doerfert }
39198b57ed09SJoseph Huber 
39209548b74aSJohannes Doerfert namespace {
39219548b74aSJohannes Doerfert 
3922b2ad63d3SJoseph Huber struct OpenMPOptCGSCCLegacyPass : public CallGraphSCCPass {
39239548b74aSJohannes Doerfert   CallGraphUpdater CGUpdater;
39249548b74aSJohannes Doerfert   static char ID;
39259548b74aSJohannes Doerfert 
3926b2ad63d3SJoseph Huber   OpenMPOptCGSCCLegacyPass() : CallGraphSCCPass(ID) {
3927b2ad63d3SJoseph Huber     initializeOpenMPOptCGSCCLegacyPassPass(*PassRegistry::getPassRegistry());
39289548b74aSJohannes Doerfert   }
39299548b74aSJohannes Doerfert 
39309548b74aSJohannes Doerfert   void getAnalysisUsage(AnalysisUsage &AU) const override {
39319548b74aSJohannes Doerfert     CallGraphSCCPass::getAnalysisUsage(AU);
39329548b74aSJohannes Doerfert   }
39339548b74aSJohannes Doerfert 
39349548b74aSJohannes Doerfert   bool runOnSCC(CallGraphSCC &CGSCC) override {
39355ccb7424SJoseph Huber     if (!containsOpenMP(CGSCC.getCallGraph().getModule()))
39369548b74aSJohannes Doerfert       return false;
39379548b74aSJohannes Doerfert     if (DisableOpenMPOptimizations || skipSCC(CGSCC))
39389548b74aSJohannes Doerfert       return false;
39399548b74aSJohannes Doerfert 
3940ee17263aSJohannes Doerfert     SmallVector<Function *, 16> SCC;
3941351d234dSRoman Lebedev     // If there are kernels in the module, we have to run on all SCC's.
3942351d234dSRoman Lebedev     for (CallGraphNode *CGN : CGSCC) {
3943351d234dSRoman Lebedev       Function *Fn = CGN->getFunction();
3944351d234dSRoman Lebedev       if (!Fn || Fn->isDeclaration())
3945351d234dSRoman Lebedev         continue;
3946ee17263aSJohannes Doerfert       SCC.push_back(Fn);
3947351d234dSRoman Lebedev     }
3948351d234dSRoman Lebedev 
39495ccb7424SJoseph Huber     if (SCC.empty())
39509548b74aSJohannes Doerfert       return false;
39519548b74aSJohannes Doerfert 
39525ccb7424SJoseph Huber     Module &M = CGSCC.getCallGraph().getModule();
39535ccb7424SJoseph Huber     KernelSet Kernels = getDeviceKernels(M);
39545ccb7424SJoseph Huber 
39559548b74aSJohannes Doerfert     CallGraph &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph();
39569548b74aSJohannes Doerfert     CGUpdater.initialize(CG, CGSCC);
39579548b74aSJohannes Doerfert 
39584d4ea9acSHuber, Joseph     // Maintain a map of functions to avoid rebuilding the ORE
39594d4ea9acSHuber, Joseph     DenseMap<Function *, std::unique_ptr<OptimizationRemarkEmitter>> OREMap;
39604d4ea9acSHuber, Joseph     auto OREGetter = [&OREMap](Function *F) -> OptimizationRemarkEmitter & {
39614d4ea9acSHuber, Joseph       std::unique_ptr<OptimizationRemarkEmitter> &ORE = OREMap[F];
39624d4ea9acSHuber, Joseph       if (!ORE)
39634d4ea9acSHuber, Joseph         ORE = std::make_unique<OptimizationRemarkEmitter>(F);
39644d4ea9acSHuber, Joseph       return *ORE;
39654d4ea9acSHuber, Joseph     };
39664d4ea9acSHuber, Joseph 
39677cfd267cSsstefan1     AnalysisGetter AG;
39687cfd267cSsstefan1     SetVector<Function *> Functions(SCC.begin(), SCC.end());
39697cfd267cSsstefan1     BumpPtrAllocator Allocator;
39705ccb7424SJoseph Huber     OMPInformationCache InfoCache(*(Functions.back()->getParent()), AG,
39715ccb7424SJoseph Huber                                   Allocator,
39725ccb7424SJoseph Huber                                   /*CGSCC*/ Functions, Kernels);
39737cfd267cSsstefan1 
397413b2fba2SJoseph Huber     unsigned MaxFixpointIterations = (isOpenMPDevice(M)) ? 128 : 32;
397530e36c9bSJoseph Huber     Attributor A(Functions, InfoCache, CGUpdater, nullptr, false, true,
397613b2fba2SJoseph Huber                  MaxFixpointIterations, OREGetter, DEBUG_TYPE);
3977b8235d2bSsstefan1 
3978b8235d2bSsstefan1     OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache, A);
3979b2ad63d3SJoseph Huber     return OMPOpt.run(false);
39809548b74aSJohannes Doerfert   }
39819548b74aSJohannes Doerfert 
39829548b74aSJohannes Doerfert   bool doFinalization(CallGraph &CG) override { return CGUpdater.finalize(); }
39839548b74aSJohannes Doerfert };
39849548b74aSJohannes Doerfert 
39859548b74aSJohannes Doerfert } // end anonymous namespace
39869548b74aSJohannes Doerfert 
39875ccb7424SJoseph Huber KernelSet llvm::omp::getDeviceKernels(Module &M) {
39885ccb7424SJoseph Huber   // TODO: Create a more cross-platform way of determining device kernels.
3989e8039ad4SJohannes Doerfert   NamedMDNode *MD = M.getOrInsertNamedMetadata("nvvm.annotations");
39905ccb7424SJoseph Huber   KernelSet Kernels;
39915ccb7424SJoseph Huber 
3992e8039ad4SJohannes Doerfert   if (!MD)
39935ccb7424SJoseph Huber     return Kernels;
3994e8039ad4SJohannes Doerfert 
3995e8039ad4SJohannes Doerfert   for (auto *Op : MD->operands()) {
3996e8039ad4SJohannes Doerfert     if (Op->getNumOperands() < 2)
3997e8039ad4SJohannes Doerfert       continue;
3998e8039ad4SJohannes Doerfert     MDString *KindID = dyn_cast<MDString>(Op->getOperand(1));
3999e8039ad4SJohannes Doerfert     if (!KindID || KindID->getString() != "kernel")
4000e8039ad4SJohannes Doerfert       continue;
4001e8039ad4SJohannes Doerfert 
4002e8039ad4SJohannes Doerfert     Function *KernelFn =
4003e8039ad4SJohannes Doerfert         mdconst::dyn_extract_or_null<Function>(Op->getOperand(0));
4004e8039ad4SJohannes Doerfert     if (!KernelFn)
4005e8039ad4SJohannes Doerfert       continue;
4006e8039ad4SJohannes Doerfert 
4007e8039ad4SJohannes Doerfert     ++NumOpenMPTargetRegionKernels;
4008e8039ad4SJohannes Doerfert 
4009e8039ad4SJohannes Doerfert     Kernels.insert(KernelFn);
4010e8039ad4SJohannes Doerfert   }
40115ccb7424SJoseph Huber 
40125ccb7424SJoseph Huber   return Kernels;
4013e8039ad4SJohannes Doerfert }
4014e8039ad4SJohannes Doerfert 
40155ccb7424SJoseph Huber bool llvm::omp::containsOpenMP(Module &M) {
40165ccb7424SJoseph Huber   Metadata *MD = M.getModuleFlag("openmp");
40175ccb7424SJoseph Huber   if (!MD)
40185ccb7424SJoseph Huber     return false;
4019dce6bc18SJohannes Doerfert 
4020e8039ad4SJohannes Doerfert   return true;
4021e8039ad4SJohannes Doerfert }
4022e8039ad4SJohannes Doerfert 
40235ccb7424SJoseph Huber bool llvm::omp::isOpenMPDevice(Module &M) {
40245ccb7424SJoseph Huber   Metadata *MD = M.getModuleFlag("openmp-device");
40255ccb7424SJoseph Huber   if (!MD)
40265ccb7424SJoseph Huber     return false;
40275ccb7424SJoseph Huber 
40285ccb7424SJoseph Huber   return true;
40299548b74aSJohannes Doerfert }
40309548b74aSJohannes Doerfert 
4031b2ad63d3SJoseph Huber char OpenMPOptCGSCCLegacyPass::ID = 0;
40329548b74aSJohannes Doerfert 
4033b2ad63d3SJoseph Huber INITIALIZE_PASS_BEGIN(OpenMPOptCGSCCLegacyPass, "openmp-opt-cgscc",
40349548b74aSJohannes Doerfert                       "OpenMP specific optimizations", false, false)
40359548b74aSJohannes Doerfert INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass)
4036b2ad63d3SJoseph Huber INITIALIZE_PASS_END(OpenMPOptCGSCCLegacyPass, "openmp-opt-cgscc",
40379548b74aSJohannes Doerfert                     "OpenMP specific optimizations", false, false)
40389548b74aSJohannes Doerfert 
4039b2ad63d3SJoseph Huber Pass *llvm::createOpenMPOptCGSCCLegacyPass() {
4040b2ad63d3SJoseph Huber   return new OpenMPOptCGSCCLegacyPass();
4041b2ad63d3SJoseph Huber }
4042