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"
249f04a0eaSJohannes Doerfert #include "llvm/ADT/SetVector.h"
259548b74aSJohannes Doerfert #include "llvm/ADT/Statistic.h"
26e6e440aeSJohannes Doerfert #include "llvm/ADT/StringRef.h"
279548b74aSJohannes Doerfert #include "llvm/Analysis/CallGraph.h"
289548b74aSJohannes Doerfert #include "llvm/Analysis/CallGraphSCCPass.h"
294d4ea9acSHuber, Joseph #include "llvm/Analysis/OptimizationRemarkEmitter.h"
303a6bfcf2SGiorgis Georgakoudis #include "llvm/Analysis/ValueTracking.h"
319548b74aSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPConstants.h"
32e28936f6SJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
33d9659bf6SJohannes Doerfert #include "llvm/IR/Assumptions.h"
34d9659bf6SJohannes Doerfert #include "llvm/IR/DiagnosticInfo.h"
35514c033dSJohannes Doerfert #include "llvm/IR/GlobalValue.h"
36d9659bf6SJohannes Doerfert #include "llvm/IR/Instruction.h"
3768abc3d2SJoseph Huber #include "llvm/IR/IntrinsicInst.h"
3827905eebSJoseph Huber #include "llvm/IR/IntrinsicsAMDGPU.h"
3927905eebSJoseph Huber #include "llvm/IR/IntrinsicsNVPTX.h"
409548b74aSJohannes Doerfert #include "llvm/InitializePasses.h"
419548b74aSJohannes Doerfert #include "llvm/Support/CommandLine.h"
429548b74aSJohannes Doerfert #include "llvm/Transforms/IPO.h"
437cfd267cSsstefan1 #include "llvm/Transforms/IPO/Attributor.h"
443a6bfcf2SGiorgis Georgakoudis #include "llvm/Transforms/Utils/BasicBlockUtils.h"
459548b74aSJohannes Doerfert #include "llvm/Transforms/Utils/CallGraphUpdater.h"
4697517055SGiorgis Georgakoudis #include "llvm/Transforms/Utils/CodeExtractor.h"
479548b74aSJohannes Doerfert 
48e6e440aeSJohannes Doerfert #include <algorithm>
49e6e440aeSJohannes Doerfert 
509548b74aSJohannes Doerfert using namespace llvm;
519548b74aSJohannes Doerfert using namespace omp;
529548b74aSJohannes Doerfert 
539548b74aSJohannes Doerfert #define DEBUG_TYPE "openmp-opt"
549548b74aSJohannes Doerfert 
559548b74aSJohannes Doerfert static cl::opt<bool> DisableOpenMPOptimizations(
569548b74aSJohannes Doerfert     "openmp-opt-disable", cl::ZeroOrMore,
579548b74aSJohannes Doerfert     cl::desc("Disable OpenMP specific optimizations."), cl::Hidden,
589548b74aSJohannes Doerfert     cl::init(false));
599548b74aSJohannes Doerfert 
603a6bfcf2SGiorgis Georgakoudis static cl::opt<bool> EnableParallelRegionMerging(
613a6bfcf2SGiorgis Georgakoudis     "openmp-opt-enable-merging", cl::ZeroOrMore,
623a6bfcf2SGiorgis Georgakoudis     cl::desc("Enable the OpenMP region merging optimization."), cl::Hidden,
633a6bfcf2SGiorgis Georgakoudis     cl::init(false));
643a6bfcf2SGiorgis Georgakoudis 
654a668604SJoseph Huber static cl::opt<bool>
664a668604SJoseph Huber     DisableInternalization("openmp-opt-disable-internalization", cl::ZeroOrMore,
674a668604SJoseph Huber                            cl::desc("Disable function internalization."),
684a668604SJoseph Huber                            cl::Hidden, cl::init(false));
694a668604SJoseph Huber 
700f426935Ssstefan1 static cl::opt<bool> PrintICVValues("openmp-print-icv-values", cl::init(false),
710f426935Ssstefan1                                     cl::Hidden);
72e8039ad4SJohannes Doerfert static cl::opt<bool> PrintOpenMPKernels("openmp-print-gpu-kernels",
73e8039ad4SJohannes Doerfert                                         cl::init(false), cl::Hidden);
740f426935Ssstefan1 
75496f8e5bSHamilton Tobon Mosquera static cl::opt<bool> HideMemoryTransferLatency(
76496f8e5bSHamilton Tobon Mosquera     "openmp-hide-memory-transfer-latency",
77496f8e5bSHamilton Tobon Mosquera     cl::desc("[WIP] Tries to hide the latency of host to device memory"
78496f8e5bSHamilton Tobon Mosquera              " transfers"),
79496f8e5bSHamilton Tobon Mosquera     cl::Hidden, cl::init(false));
80496f8e5bSHamilton Tobon Mosquera 
81cd0dd8ecSJoseph Huber static cl::opt<bool> DisableOpenMPOptDeglobalization(
82cd0dd8ecSJoseph Huber     "openmp-opt-disable-deglobalization", cl::ZeroOrMore,
83cd0dd8ecSJoseph Huber     cl::desc("Disable OpenMP optimizations involving deglobalization."),
84cd0dd8ecSJoseph Huber     cl::Hidden, cl::init(false));
85cd0dd8ecSJoseph Huber 
86cd0dd8ecSJoseph Huber static cl::opt<bool> DisableOpenMPOptSPMDization(
87cd0dd8ecSJoseph Huber     "openmp-opt-disable-spmdization", cl::ZeroOrMore,
88cd0dd8ecSJoseph Huber     cl::desc("Disable OpenMP optimizations involving SPMD-ization."),
89cd0dd8ecSJoseph Huber     cl::Hidden, cl::init(false));
90cd0dd8ecSJoseph Huber 
91cd0dd8ecSJoseph Huber static cl::opt<bool> DisableOpenMPOptFolding(
92cd0dd8ecSJoseph Huber     "openmp-opt-disable-folding", cl::ZeroOrMore,
93cd0dd8ecSJoseph Huber     cl::desc("Disable OpenMP optimizations involving folding."), cl::Hidden,
94cd0dd8ecSJoseph Huber     cl::init(false));
95cd0dd8ecSJoseph Huber 
96cd0dd8ecSJoseph Huber static cl::opt<bool> DisableOpenMPOptStateMachineRewrite(
97cd0dd8ecSJoseph Huber     "openmp-opt-disable-state-machine-rewrite", cl::ZeroOrMore,
98cd0dd8ecSJoseph Huber     cl::desc("Disable OpenMP optimizations that replace the state machine."),
99cd0dd8ecSJoseph Huber     cl::Hidden, cl::init(false));
100cd0dd8ecSJoseph Huber 
101339aa765SJoseph Huber static cl::opt<bool> PrintModuleAfterOptimizations(
102339aa765SJoseph Huber     "openmp-opt-print-module", cl::ZeroOrMore,
103339aa765SJoseph Huber     cl::desc("Print the current module after OpenMP optimizations."),
104339aa765SJoseph Huber     cl::Hidden, cl::init(false));
105339aa765SJoseph Huber 
10629a74a39SJoseph Huber static cl::opt<bool> AlwaysInlineDeviceFunctions(
10729a74a39SJoseph Huber     "openmp-opt-inline-device", cl::ZeroOrMore,
10829a74a39SJoseph Huber     cl::desc("Inline all applicible functions on the device."), cl::Hidden,
10929a74a39SJoseph Huber     cl::init(false));
11029a74a39SJoseph Huber 
1117eb899cbSJoseph Huber static cl::opt<bool>
1127eb899cbSJoseph Huber     EnableVerboseRemarks("openmp-opt-verbose-remarks", cl::ZeroOrMore,
1137eb899cbSJoseph Huber                          cl::desc("Enables more verbose remarks."), cl::Hidden,
1147eb899cbSJoseph Huber                          cl::init(false));
1157eb899cbSJoseph Huber 
116f074a6a0SJoseph Huber static cl::opt<unsigned>
117f074a6a0SJoseph Huber     SetFixpointIterations("openmp-opt-max-iterations", cl::Hidden,
118f074a6a0SJoseph Huber                           cl::desc("Maximal number of attributor iterations."),
119f074a6a0SJoseph Huber                           cl::init(256));
120f074a6a0SJoseph Huber 
1219548b74aSJohannes Doerfert STATISTIC(NumOpenMPRuntimeCallsDeduplicated,
1229548b74aSJohannes Doerfert           "Number of OpenMP runtime calls deduplicated");
12355eb714aSRoman Lebedev STATISTIC(NumOpenMPParallelRegionsDeleted,
12455eb714aSRoman Lebedev           "Number of OpenMP parallel regions deleted");
1259548b74aSJohannes Doerfert STATISTIC(NumOpenMPRuntimeFunctionsIdentified,
1269548b74aSJohannes Doerfert           "Number of OpenMP runtime functions identified");
1279548b74aSJohannes Doerfert STATISTIC(NumOpenMPRuntimeFunctionUsesIdentified,
1289548b74aSJohannes Doerfert           "Number of OpenMP runtime function uses identified");
129e8039ad4SJohannes Doerfert STATISTIC(NumOpenMPTargetRegionKernels,
130e8039ad4SJohannes Doerfert           "Number of OpenMP target region entry points (=kernels) identified");
131514c033dSJohannes Doerfert STATISTIC(NumOpenMPTargetRegionKernelsSPMD,
132514c033dSJohannes Doerfert           "Number of OpenMP target region entry points (=kernels) executed in "
133514c033dSJohannes Doerfert           "SPMD-mode instead of generic-mode");
134d9659bf6SJohannes Doerfert STATISTIC(NumOpenMPTargetRegionKernelsWithoutStateMachine,
135d9659bf6SJohannes Doerfert           "Number of OpenMP target region entry points (=kernels) executed in "
136d9659bf6SJohannes Doerfert           "generic-mode without a state machines");
137d9659bf6SJohannes Doerfert STATISTIC(NumOpenMPTargetRegionKernelsCustomStateMachineWithFallback,
138d9659bf6SJohannes Doerfert           "Number of OpenMP target region entry points (=kernels) executed in "
139d9659bf6SJohannes Doerfert           "generic-mode with customized state machines with fallback");
140d9659bf6SJohannes Doerfert STATISTIC(NumOpenMPTargetRegionKernelsCustomStateMachineWithoutFallback,
141d9659bf6SJohannes Doerfert           "Number of OpenMP target region entry points (=kernels) executed in "
142d9659bf6SJohannes Doerfert           "generic-mode with customized state machines without fallback");
1435b0581aeSJohannes Doerfert STATISTIC(
1445b0581aeSJohannes Doerfert     NumOpenMPParallelRegionsReplacedInGPUStateMachine,
1455b0581aeSJohannes Doerfert     "Number of OpenMP parallel regions replaced with ID in GPU state machines");
1463a6bfcf2SGiorgis Georgakoudis STATISTIC(NumOpenMPParallelRegionsMerged,
1473a6bfcf2SGiorgis Georgakoudis           "Number of OpenMP parallel regions merged");
1486fc51c9fSJoseph Huber STATISTIC(NumBytesMovedToSharedMemory,
1496fc51c9fSJoseph Huber           "Amount of memory pushed to shared memory");
1509548b74aSJohannes Doerfert 
151263c4a3cSrathod-sahaab #if !defined(NDEBUG)
1529548b74aSJohannes Doerfert static constexpr auto TAG = "[" DEBUG_TYPE "]";
153a50c0b0dSMikael Holmen #endif
1549548b74aSJohannes Doerfert 
1559548b74aSJohannes Doerfert namespace {
1569548b74aSJohannes Doerfert 
1576fc51c9fSJoseph Huber struct AAHeapToShared;
1586fc51c9fSJoseph Huber 
159b8235d2bSsstefan1 struct AAICVTracker;
160b8235d2bSsstefan1 
1617cfd267cSsstefan1 /// OpenMP specific information. For now, stores RFIs and ICVs also needed for
1627cfd267cSsstefan1 /// Attributor runs.
1637cfd267cSsstefan1 struct OMPInformationCache : public InformationCache {
1647cfd267cSsstefan1   OMPInformationCache(Module &M, AnalysisGetter &AG,
165624d34afSJohannes Doerfert                       BumpPtrAllocator &Allocator, SetVector<Function *> &CGSCC,
166*86cdff0eSEli Friedman                       KernelSet &Kernels)
167624d34afSJohannes Doerfert       : InformationCache(M, AG, Allocator, &CGSCC), OMPBuilder(M),
168624d34afSJohannes Doerfert         Kernels(Kernels) {
169624d34afSJohannes Doerfert 
17061238d26Ssstefan1     OMPBuilder.initialize();
1719548b74aSJohannes Doerfert     initializeRuntimeFunctions();
1720f426935Ssstefan1     initializeInternalControlVars();
1739548b74aSJohannes Doerfert   }
1749548b74aSJohannes Doerfert 
1750f426935Ssstefan1   /// Generic information that describes an internal control variable.
1760f426935Ssstefan1   struct InternalControlVarInfo {
1770f426935Ssstefan1     /// The kind, as described by InternalControlVar enum.
1780f426935Ssstefan1     InternalControlVar Kind;
1790f426935Ssstefan1 
1800f426935Ssstefan1     /// The name of the ICV.
1810f426935Ssstefan1     StringRef Name;
1820f426935Ssstefan1 
1830f426935Ssstefan1     /// Environment variable associated with this ICV.
1840f426935Ssstefan1     StringRef EnvVarName;
1850f426935Ssstefan1 
1860f426935Ssstefan1     /// Initial value kind.
1870f426935Ssstefan1     ICVInitValue InitKind;
1880f426935Ssstefan1 
1890f426935Ssstefan1     /// Initial value.
1900f426935Ssstefan1     ConstantInt *InitValue;
1910f426935Ssstefan1 
1920f426935Ssstefan1     /// Setter RTL function associated with this ICV.
1930f426935Ssstefan1     RuntimeFunction Setter;
1940f426935Ssstefan1 
1950f426935Ssstefan1     /// Getter RTL function associated with this ICV.
1960f426935Ssstefan1     RuntimeFunction Getter;
1970f426935Ssstefan1 
1980f426935Ssstefan1     /// RTL Function corresponding to the override clause of this ICV
1990f426935Ssstefan1     RuntimeFunction Clause;
2000f426935Ssstefan1   };
2010f426935Ssstefan1 
2029548b74aSJohannes Doerfert   /// Generic information that describes a runtime function
2039548b74aSJohannes Doerfert   struct RuntimeFunctionInfo {
2048855fec3SJohannes Doerfert 
2059548b74aSJohannes Doerfert     /// The kind, as described by the RuntimeFunction enum.
2069548b74aSJohannes Doerfert     RuntimeFunction Kind;
2079548b74aSJohannes Doerfert 
2089548b74aSJohannes Doerfert     /// The name of the function.
2099548b74aSJohannes Doerfert     StringRef Name;
2109548b74aSJohannes Doerfert 
2119548b74aSJohannes Doerfert     /// Flag to indicate a variadic function.
2129548b74aSJohannes Doerfert     bool IsVarArg;
2139548b74aSJohannes Doerfert 
2149548b74aSJohannes Doerfert     /// The return type of the function.
2159548b74aSJohannes Doerfert     Type *ReturnType;
2169548b74aSJohannes Doerfert 
2179548b74aSJohannes Doerfert     /// The argument types of the function.
2189548b74aSJohannes Doerfert     SmallVector<Type *, 8> ArgumentTypes;
2199548b74aSJohannes Doerfert 
2209548b74aSJohannes Doerfert     /// The declaration if available.
221f09f4b26SJohannes Doerfert     Function *Declaration = nullptr;
2229548b74aSJohannes Doerfert 
2239548b74aSJohannes Doerfert     /// Uses of this runtime function per function containing the use.
2248855fec3SJohannes Doerfert     using UseVector = SmallVector<Use *, 16>;
2258855fec3SJohannes Doerfert 
226b8235d2bSsstefan1     /// Clear UsesMap for runtime function.
227b8235d2bSsstefan1     void clearUsesMap() { UsesMap.clear(); }
228b8235d2bSsstefan1 
22954bd3751SJohannes Doerfert     /// Boolean conversion that is true if the runtime function was found.
23054bd3751SJohannes Doerfert     operator bool() const { return Declaration; }
23154bd3751SJohannes Doerfert 
2328855fec3SJohannes Doerfert     /// Return the vector of uses in function \p F.
2338855fec3SJohannes Doerfert     UseVector &getOrCreateUseVector(Function *F) {
234b8235d2bSsstefan1       std::shared_ptr<UseVector> &UV = UsesMap[F];
2358855fec3SJohannes Doerfert       if (!UV)
236b8235d2bSsstefan1         UV = std::make_shared<UseVector>();
2378855fec3SJohannes Doerfert       return *UV;
2388855fec3SJohannes Doerfert     }
2398855fec3SJohannes Doerfert 
2408855fec3SJohannes Doerfert     /// Return the vector of uses in function \p F or `nullptr` if there are
2418855fec3SJohannes Doerfert     /// none.
2428855fec3SJohannes Doerfert     const UseVector *getUseVector(Function &F) const {
24395e57072SDavid Blaikie       auto I = UsesMap.find(&F);
24495e57072SDavid Blaikie       if (I != UsesMap.end())
24595e57072SDavid Blaikie         return I->second.get();
24695e57072SDavid Blaikie       return nullptr;
2478855fec3SJohannes Doerfert     }
2488855fec3SJohannes Doerfert 
2498855fec3SJohannes Doerfert     /// Return how many functions contain uses of this runtime function.
2508855fec3SJohannes Doerfert     size_t getNumFunctionsWithUses() const { return UsesMap.size(); }
2519548b74aSJohannes Doerfert 
2529548b74aSJohannes Doerfert     /// Return the number of arguments (or the minimal number for variadic
2539548b74aSJohannes Doerfert     /// functions).
2549548b74aSJohannes Doerfert     size_t getNumArgs() const { return ArgumentTypes.size(); }
2559548b74aSJohannes Doerfert 
2569548b74aSJohannes Doerfert     /// Run the callback \p CB on each use and forget the use if the result is
2579548b74aSJohannes Doerfert     /// true. The callback will be fed the function in which the use was
2589548b74aSJohannes Doerfert     /// encountered as second argument.
259624d34afSJohannes Doerfert     void foreachUse(SmallVectorImpl<Function *> &SCC,
260624d34afSJohannes Doerfert                     function_ref<bool(Use &, Function &)> CB) {
261624d34afSJohannes Doerfert       for (Function *F : SCC)
262624d34afSJohannes Doerfert         foreachUse(CB, F);
263e099c7b6Ssstefan1     }
264e099c7b6Ssstefan1 
265e099c7b6Ssstefan1     /// Run the callback \p CB on each use within the function \p F and forget
266e099c7b6Ssstefan1     /// the use if the result is true.
267624d34afSJohannes Doerfert     void foreachUse(function_ref<bool(Use &, Function &)> CB, Function *F) {
2688855fec3SJohannes Doerfert       SmallVector<unsigned, 8> ToBeDeleted;
2699548b74aSJohannes Doerfert       ToBeDeleted.clear();
270e099c7b6Ssstefan1 
2718855fec3SJohannes Doerfert       unsigned Idx = 0;
272624d34afSJohannes Doerfert       UseVector &UV = getOrCreateUseVector(F);
273e099c7b6Ssstefan1 
2748855fec3SJohannes Doerfert       for (Use *U : UV) {
275e099c7b6Ssstefan1         if (CB(*U, *F))
2768855fec3SJohannes Doerfert           ToBeDeleted.push_back(Idx);
2778855fec3SJohannes Doerfert         ++Idx;
2788855fec3SJohannes Doerfert       }
2798855fec3SJohannes Doerfert 
2808855fec3SJohannes Doerfert       // Remove the to-be-deleted indices in reverse order as prior
281b726c557SJohannes Doerfert       // modifications will not modify the smaller indices.
2828855fec3SJohannes Doerfert       while (!ToBeDeleted.empty()) {
2838855fec3SJohannes Doerfert         unsigned Idx = ToBeDeleted.pop_back_val();
2848855fec3SJohannes Doerfert         UV[Idx] = UV.back();
2858855fec3SJohannes Doerfert         UV.pop_back();
2869548b74aSJohannes Doerfert       }
2879548b74aSJohannes Doerfert     }
2888855fec3SJohannes Doerfert 
2898855fec3SJohannes Doerfert   private:
2908855fec3SJohannes Doerfert     /// Map from functions to all uses of this runtime function contained in
2918855fec3SJohannes Doerfert     /// them.
292b8235d2bSsstefan1     DenseMap<Function *, std::shared_ptr<UseVector>> UsesMap;
293d9659bf6SJohannes Doerfert 
294d9659bf6SJohannes Doerfert   public:
295d9659bf6SJohannes Doerfert     /// Iterators for the uses of this runtime function.
296d9659bf6SJohannes Doerfert     decltype(UsesMap)::iterator begin() { return UsesMap.begin(); }
297d9659bf6SJohannes Doerfert     decltype(UsesMap)::iterator end() { return UsesMap.end(); }
2989548b74aSJohannes Doerfert   };
2999548b74aSJohannes Doerfert 
3007cfd267cSsstefan1   /// An OpenMP-IR-Builder instance
3017cfd267cSsstefan1   OpenMPIRBuilder OMPBuilder;
3027cfd267cSsstefan1 
3037cfd267cSsstefan1   /// Map from runtime function kind to the runtime function description.
3047cfd267cSsstefan1   EnumeratedArray<RuntimeFunctionInfo, RuntimeFunction,
3057cfd267cSsstefan1                   RuntimeFunction::OMPRTL___last>
3067cfd267cSsstefan1       RFIs;
3077cfd267cSsstefan1 
308d9659bf6SJohannes Doerfert   /// Map from function declarations/definitions to their runtime enum type.
309d9659bf6SJohannes Doerfert   DenseMap<Function *, RuntimeFunction> RuntimeFunctionIDMap;
310d9659bf6SJohannes Doerfert 
3110f426935Ssstefan1   /// Map from ICV kind to the ICV description.
3120f426935Ssstefan1   EnumeratedArray<InternalControlVarInfo, InternalControlVar,
3130f426935Ssstefan1                   InternalControlVar::ICV___last>
3140f426935Ssstefan1       ICVs;
3150f426935Ssstefan1 
3160f426935Ssstefan1   /// Helper to initialize all internal control variable information for those
3170f426935Ssstefan1   /// defined in OMPKinds.def.
3180f426935Ssstefan1   void initializeInternalControlVars() {
3190f426935Ssstefan1 #define ICV_RT_SET(_Name, RTL)                                                 \
3200f426935Ssstefan1   {                                                                            \
3210f426935Ssstefan1     auto &ICV = ICVs[_Name];                                                   \
3220f426935Ssstefan1     ICV.Setter = RTL;                                                          \
3230f426935Ssstefan1   }
3240f426935Ssstefan1 #define ICV_RT_GET(Name, RTL)                                                  \
3250f426935Ssstefan1   {                                                                            \
3260f426935Ssstefan1     auto &ICV = ICVs[Name];                                                    \
3270f426935Ssstefan1     ICV.Getter = RTL;                                                          \
3280f426935Ssstefan1   }
3290f426935Ssstefan1 #define ICV_DATA_ENV(Enum, _Name, _EnvVarName, Init)                           \
3300f426935Ssstefan1   {                                                                            \
3310f426935Ssstefan1     auto &ICV = ICVs[Enum];                                                    \
3320f426935Ssstefan1     ICV.Name = _Name;                                                          \
3330f426935Ssstefan1     ICV.Kind = Enum;                                                           \
3340f426935Ssstefan1     ICV.InitKind = Init;                                                       \
3350f426935Ssstefan1     ICV.EnvVarName = _EnvVarName;                                              \
3360f426935Ssstefan1     switch (ICV.InitKind) {                                                    \
337951e43f3Ssstefan1     case ICV_IMPLEMENTATION_DEFINED:                                           \
3380f426935Ssstefan1       ICV.InitValue = nullptr;                                                 \
3390f426935Ssstefan1       break;                                                                   \
340951e43f3Ssstefan1     case ICV_ZERO:                                                             \
3416aab27baSsstefan1       ICV.InitValue = ConstantInt::get(                                        \
3426aab27baSsstefan1           Type::getInt32Ty(OMPBuilder.Int32->getContext()), 0);                \
3430f426935Ssstefan1       break;                                                                   \
344951e43f3Ssstefan1     case ICV_FALSE:                                                            \
3456aab27baSsstefan1       ICV.InitValue = ConstantInt::getFalse(OMPBuilder.Int1->getContext());    \
3460f426935Ssstefan1       break;                                                                   \
347951e43f3Ssstefan1     case ICV_LAST:                                                             \
3480f426935Ssstefan1       break;                                                                   \
3490f426935Ssstefan1     }                                                                          \
3500f426935Ssstefan1   }
3510f426935Ssstefan1 #include "llvm/Frontend/OpenMP/OMPKinds.def"
3520f426935Ssstefan1   }
3530f426935Ssstefan1 
3547cfd267cSsstefan1   /// Returns true if the function declaration \p F matches the runtime
3557cfd267cSsstefan1   /// function types, that is, return type \p RTFRetType, and argument types
3567cfd267cSsstefan1   /// \p RTFArgTypes.
3577cfd267cSsstefan1   static bool declMatchesRTFTypes(Function *F, Type *RTFRetType,
3587cfd267cSsstefan1                                   SmallVector<Type *, 8> &RTFArgTypes) {
3597cfd267cSsstefan1     // TODO: We should output information to the user (under debug output
3607cfd267cSsstefan1     //       and via remarks).
3617cfd267cSsstefan1 
3627cfd267cSsstefan1     if (!F)
3637cfd267cSsstefan1       return false;
3647cfd267cSsstefan1     if (F->getReturnType() != RTFRetType)
3657cfd267cSsstefan1       return false;
3667cfd267cSsstefan1     if (F->arg_size() != RTFArgTypes.size())
3677cfd267cSsstefan1       return false;
3687cfd267cSsstefan1 
369c11ebfeaSJoseph Huber     auto *RTFTyIt = RTFArgTypes.begin();
3707cfd267cSsstefan1     for (Argument &Arg : F->args()) {
3717cfd267cSsstefan1       if (Arg.getType() != *RTFTyIt)
3727cfd267cSsstefan1         return false;
3737cfd267cSsstefan1 
3747cfd267cSsstefan1       ++RTFTyIt;
3757cfd267cSsstefan1     }
3767cfd267cSsstefan1 
3777cfd267cSsstefan1     return true;
3787cfd267cSsstefan1   }
3797cfd267cSsstefan1 
380b726c557SJohannes Doerfert   // Helper to collect all uses of the declaration in the UsesMap.
381b8235d2bSsstefan1   unsigned collectUses(RuntimeFunctionInfo &RFI, bool CollectStats = true) {
3827cfd267cSsstefan1     unsigned NumUses = 0;
3837cfd267cSsstefan1     if (!RFI.Declaration)
3847cfd267cSsstefan1       return NumUses;
3857cfd267cSsstefan1     OMPBuilder.addAttributes(RFI.Kind, *RFI.Declaration);
3867cfd267cSsstefan1 
387b8235d2bSsstefan1     if (CollectStats) {
3887cfd267cSsstefan1       NumOpenMPRuntimeFunctionsIdentified += 1;
3897cfd267cSsstefan1       NumOpenMPRuntimeFunctionUsesIdentified += RFI.Declaration->getNumUses();
390b8235d2bSsstefan1     }
3917cfd267cSsstefan1 
3927cfd267cSsstefan1     // TODO: We directly convert uses into proper calls and unknown uses.
3937cfd267cSsstefan1     for (Use &U : RFI.Declaration->uses()) {
3947cfd267cSsstefan1       if (Instruction *UserI = dyn_cast<Instruction>(U.getUser())) {
3957cfd267cSsstefan1         if (ModuleSlice.count(UserI->getFunction())) {
3967cfd267cSsstefan1           RFI.getOrCreateUseVector(UserI->getFunction()).push_back(&U);
3977cfd267cSsstefan1           ++NumUses;
3987cfd267cSsstefan1         }
3997cfd267cSsstefan1       } else {
4007cfd267cSsstefan1         RFI.getOrCreateUseVector(nullptr).push_back(&U);
4017cfd267cSsstefan1         ++NumUses;
4027cfd267cSsstefan1       }
4037cfd267cSsstefan1     }
4047cfd267cSsstefan1     return NumUses;
405b8235d2bSsstefan1   }
4067cfd267cSsstefan1 
40797517055SGiorgis Georgakoudis   // Helper function to recollect uses of a runtime function.
40897517055SGiorgis Georgakoudis   void recollectUsesForFunction(RuntimeFunction RTF) {
40997517055SGiorgis Georgakoudis     auto &RFI = RFIs[RTF];
410b8235d2bSsstefan1     RFI.clearUsesMap();
411b8235d2bSsstefan1     collectUses(RFI, /*CollectStats*/ false);
412b8235d2bSsstefan1   }
41397517055SGiorgis Georgakoudis 
41497517055SGiorgis Georgakoudis   // Helper function to recollect uses of all runtime functions.
41597517055SGiorgis Georgakoudis   void recollectUses() {
41697517055SGiorgis Georgakoudis     for (int Idx = 0; Idx < RFIs.size(); ++Idx)
41797517055SGiorgis Georgakoudis       recollectUsesForFunction(static_cast<RuntimeFunction>(Idx));
418b8235d2bSsstefan1   }
419b8235d2bSsstefan1 
420b8235d2bSsstefan1   /// Helper to initialize all runtime function information for those defined
421b8235d2bSsstefan1   /// in OpenMPKinds.def.
422b8235d2bSsstefan1   void initializeRuntimeFunctions() {
4237cfd267cSsstefan1     Module &M = *((*ModuleSlice.begin())->getParent());
4247cfd267cSsstefan1 
4256aab27baSsstefan1     // Helper macros for handling __VA_ARGS__ in OMP_RTL
4266aab27baSsstefan1 #define OMP_TYPE(VarName, ...)                                                 \
4276aab27baSsstefan1   Type *VarName = OMPBuilder.VarName;                                          \
4286aab27baSsstefan1   (void)VarName;
4296aab27baSsstefan1 
4306aab27baSsstefan1 #define OMP_ARRAY_TYPE(VarName, ...)                                           \
4316aab27baSsstefan1   ArrayType *VarName##Ty = OMPBuilder.VarName##Ty;                             \
4326aab27baSsstefan1   (void)VarName##Ty;                                                           \
4336aab27baSsstefan1   PointerType *VarName##PtrTy = OMPBuilder.VarName##PtrTy;                     \
4346aab27baSsstefan1   (void)VarName##PtrTy;
4356aab27baSsstefan1 
4366aab27baSsstefan1 #define OMP_FUNCTION_TYPE(VarName, ...)                                        \
4376aab27baSsstefan1   FunctionType *VarName = OMPBuilder.VarName;                                  \
4386aab27baSsstefan1   (void)VarName;                                                               \
4396aab27baSsstefan1   PointerType *VarName##Ptr = OMPBuilder.VarName##Ptr;                         \
4406aab27baSsstefan1   (void)VarName##Ptr;
4416aab27baSsstefan1 
4426aab27baSsstefan1 #define OMP_STRUCT_TYPE(VarName, ...)                                          \
4436aab27baSsstefan1   StructType *VarName = OMPBuilder.VarName;                                    \
4446aab27baSsstefan1   (void)VarName;                                                               \
4456aab27baSsstefan1   PointerType *VarName##Ptr = OMPBuilder.VarName##Ptr;                         \
4466aab27baSsstefan1   (void)VarName##Ptr;
4476aab27baSsstefan1 
4487cfd267cSsstefan1 #define OMP_RTL(_Enum, _Name, _IsVarArg, _ReturnType, ...)                     \
4497cfd267cSsstefan1   {                                                                            \
4507cfd267cSsstefan1     SmallVector<Type *, 8> ArgsTypes({__VA_ARGS__});                           \
4517cfd267cSsstefan1     Function *F = M.getFunction(_Name);                                        \
452eef6601bSJoseph Huber     RTLFunctions.insert(F);                                                    \
4536aab27baSsstefan1     if (declMatchesRTFTypes(F, OMPBuilder._ReturnType, ArgsTypes)) {           \
454d9659bf6SJohannes Doerfert       RuntimeFunctionIDMap[F] = _Enum;                                         \
45516206d17SJoseph Huber       F->removeFnAttr(Attribute::NoInline);                                    \
4567cfd267cSsstefan1       auto &RFI = RFIs[_Enum];                                                 \
4577cfd267cSsstefan1       RFI.Kind = _Enum;                                                        \
4587cfd267cSsstefan1       RFI.Name = _Name;                                                        \
4597cfd267cSsstefan1       RFI.IsVarArg = _IsVarArg;                                                \
4606aab27baSsstefan1       RFI.ReturnType = OMPBuilder._ReturnType;                                 \
4617cfd267cSsstefan1       RFI.ArgumentTypes = std::move(ArgsTypes);                                \
4627cfd267cSsstefan1       RFI.Declaration = F;                                                     \
463b8235d2bSsstefan1       unsigned NumUses = collectUses(RFI);                                     \
4647cfd267cSsstefan1       (void)NumUses;                                                           \
4657cfd267cSsstefan1       LLVM_DEBUG({                                                             \
4667cfd267cSsstefan1         dbgs() << TAG << RFI.Name << (RFI.Declaration ? "" : " not")           \
4677cfd267cSsstefan1                << " found\n";                                                  \
4687cfd267cSsstefan1         if (RFI.Declaration)                                                   \
4697cfd267cSsstefan1           dbgs() << TAG << "-> got " << NumUses << " uses in "                 \
4707cfd267cSsstefan1                  << RFI.getNumFunctionsWithUses()                              \
4717cfd267cSsstefan1                  << " different functions.\n";                                 \
4727cfd267cSsstefan1       });                                                                      \
4737cfd267cSsstefan1     }                                                                          \
4747cfd267cSsstefan1   }
4757cfd267cSsstefan1 #include "llvm/Frontend/OpenMP/OMPKinds.def"
4767cfd267cSsstefan1 
4777cfd267cSsstefan1     // TODO: We should attach the attributes defined in OMPKinds.def.
4787cfd267cSsstefan1   }
479e8039ad4SJohannes Doerfert 
480e8039ad4SJohannes Doerfert   /// Collection of known kernels (\see Kernel) in the module.
481*86cdff0eSEli Friedman   KernelSet &Kernels;
482eef6601bSJoseph Huber 
483eef6601bSJoseph Huber   /// Collection of known OpenMP runtime functions..
484eef6601bSJoseph Huber   DenseSet<const Function *> RTLFunctions;
4857cfd267cSsstefan1 };
4867cfd267cSsstefan1 
487d9659bf6SJohannes Doerfert template <typename Ty, bool InsertInvalidates = true>
4881a7f7790SShilei Tian struct BooleanStateWithSetVector : public BooleanState {
4891a7f7790SShilei Tian   bool contains(const Ty &Elem) const { return Set.contains(Elem); }
4901a7f7790SShilei Tian   bool insert(const Ty &Elem) {
491d9659bf6SJohannes Doerfert     if (InsertInvalidates)
492d9659bf6SJohannes Doerfert       BooleanState::indicatePessimisticFixpoint();
493d9659bf6SJohannes Doerfert     return Set.insert(Elem);
494d9659bf6SJohannes Doerfert   }
495d9659bf6SJohannes Doerfert 
4961a7f7790SShilei Tian   const Ty &operator[](int Idx) const { return Set[Idx]; }
4971a7f7790SShilei Tian   bool operator==(const BooleanStateWithSetVector &RHS) const {
498d9659bf6SJohannes Doerfert     return BooleanState::operator==(RHS) && Set == RHS.Set;
499d9659bf6SJohannes Doerfert   }
5001a7f7790SShilei Tian   bool operator!=(const BooleanStateWithSetVector &RHS) const {
501d9659bf6SJohannes Doerfert     return !(*this == RHS);
502d9659bf6SJohannes Doerfert   }
503d9659bf6SJohannes Doerfert 
504d9659bf6SJohannes Doerfert   bool empty() const { return Set.empty(); }
505d9659bf6SJohannes Doerfert   size_t size() const { return Set.size(); }
506d9659bf6SJohannes Doerfert 
507d9659bf6SJohannes Doerfert   /// "Clamp" this state with \p RHS.
5081a7f7790SShilei Tian   BooleanStateWithSetVector &operator^=(const BooleanStateWithSetVector &RHS) {
509d9659bf6SJohannes Doerfert     BooleanState::operator^=(RHS);
510d9659bf6SJohannes Doerfert     Set.insert(RHS.Set.begin(), RHS.Set.end());
511d9659bf6SJohannes Doerfert     return *this;
512d9659bf6SJohannes Doerfert   }
513d9659bf6SJohannes Doerfert 
514d9659bf6SJohannes Doerfert private:
515d9659bf6SJohannes Doerfert   /// A set to keep track of elements.
5161a7f7790SShilei Tian   SetVector<Ty> Set;
517d9659bf6SJohannes Doerfert 
518d9659bf6SJohannes Doerfert public:
519d9659bf6SJohannes Doerfert   typename decltype(Set)::iterator begin() { return Set.begin(); }
520d9659bf6SJohannes Doerfert   typename decltype(Set)::iterator end() { return Set.end(); }
521d9659bf6SJohannes Doerfert   typename decltype(Set)::const_iterator begin() const { return Set.begin(); }
522d9659bf6SJohannes Doerfert   typename decltype(Set)::const_iterator end() const { return Set.end(); }
523d9659bf6SJohannes Doerfert };
524d9659bf6SJohannes Doerfert 
5251a7f7790SShilei Tian template <typename Ty, bool InsertInvalidates = true>
5261a7f7790SShilei Tian using BooleanStateWithPtrSetVector =
5271a7f7790SShilei Tian     BooleanStateWithSetVector<Ty *, InsertInvalidates>;
5281a7f7790SShilei Tian 
529d9659bf6SJohannes Doerfert struct KernelInfoState : AbstractState {
530d9659bf6SJohannes Doerfert   /// Flag to track if we reached a fixpoint.
531d9659bf6SJohannes Doerfert   bool IsAtFixpoint = false;
532d9659bf6SJohannes Doerfert 
533d9659bf6SJohannes Doerfert   /// The parallel regions (identified by the outlined parallel functions) that
534d9659bf6SJohannes Doerfert   /// can be reached from the associated function.
535d9659bf6SJohannes Doerfert   BooleanStateWithPtrSetVector<Function, /* InsertInvalidates */ false>
536d9659bf6SJohannes Doerfert       ReachedKnownParallelRegions;
537d9659bf6SJohannes Doerfert 
538d9659bf6SJohannes Doerfert   /// State to track what parallel region we might reach.
539d9659bf6SJohannes Doerfert   BooleanStateWithPtrSetVector<CallBase> ReachedUnknownParallelRegions;
540d9659bf6SJohannes Doerfert 
541514c033dSJohannes Doerfert   /// State to track if we are in SPMD-mode, assumed or know, and why we decided
542e8439ec8SGiorgis Georgakoudis   /// we cannot be. If it is assumed, then RequiresFullRuntime should also be
543e8439ec8SGiorgis Georgakoudis   /// false.
54429a3e3ddSGiorgis Georgakoudis   BooleanStateWithPtrSetVector<Instruction, false> SPMDCompatibilityTracker;
545514c033dSJohannes Doerfert 
546d9659bf6SJohannes Doerfert   /// The __kmpc_target_init call in this kernel, if any. If we find more than
547d9659bf6SJohannes Doerfert   /// one we abort as the kernel is malformed.
548d9659bf6SJohannes Doerfert   CallBase *KernelInitCB = nullptr;
549d9659bf6SJohannes Doerfert 
550d9659bf6SJohannes Doerfert   /// The __kmpc_target_deinit call in this kernel, if any. If we find more than
551d9659bf6SJohannes Doerfert   /// one we abort as the kernel is malformed.
552d9659bf6SJohannes Doerfert   CallBase *KernelDeinitCB = nullptr;
553d9659bf6SJohannes Doerfert 
554ca662297SShilei Tian   /// Flag to indicate if the associated function is a kernel entry.
555ca662297SShilei Tian   bool IsKernelEntry = false;
556ca662297SShilei Tian 
557ca662297SShilei Tian   /// State to track what kernel entries can reach the associated function.
558ca662297SShilei Tian   BooleanStateWithPtrSetVector<Function, false> ReachingKernelEntries;
559ca662297SShilei Tian 
560e97e0a4fSShilei Tian   /// State to indicate if we can track parallel level of the associated
561e97e0a4fSShilei Tian   /// function. We will give up tracking if we encounter unknown caller or the
562e97e0a4fSShilei Tian   /// caller is __kmpc_parallel_51.
563e97e0a4fSShilei Tian   BooleanStateWithSetVector<uint8_t> ParallelLevels;
564e97e0a4fSShilei Tian 
565d9659bf6SJohannes Doerfert   /// Abstract State interface
566d9659bf6SJohannes Doerfert   ///{
567d9659bf6SJohannes Doerfert 
568d9659bf6SJohannes Doerfert   KernelInfoState() {}
569d9659bf6SJohannes Doerfert   KernelInfoState(bool BestState) {
570d9659bf6SJohannes Doerfert     if (!BestState)
571d9659bf6SJohannes Doerfert       indicatePessimisticFixpoint();
572d9659bf6SJohannes Doerfert   }
573d9659bf6SJohannes Doerfert 
574d9659bf6SJohannes Doerfert   /// See AbstractState::isValidState(...)
575d9659bf6SJohannes Doerfert   bool isValidState() const override { return true; }
576d9659bf6SJohannes Doerfert 
577d9659bf6SJohannes Doerfert   /// See AbstractState::isAtFixpoint(...)
578d9659bf6SJohannes Doerfert   bool isAtFixpoint() const override { return IsAtFixpoint; }
579d9659bf6SJohannes Doerfert 
580d9659bf6SJohannes Doerfert   /// See AbstractState::indicatePessimisticFixpoint(...)
581d9659bf6SJohannes Doerfert   ChangeStatus indicatePessimisticFixpoint() override {
582d9659bf6SJohannes Doerfert     IsAtFixpoint = true;
583c6457dcaSJohannes Doerfert     ReachingKernelEntries.indicatePessimisticFixpoint();
584514c033dSJohannes Doerfert     SPMDCompatibilityTracker.indicatePessimisticFixpoint();
585c6457dcaSJohannes Doerfert     ReachedKnownParallelRegions.indicatePessimisticFixpoint();
586d9659bf6SJohannes Doerfert     ReachedUnknownParallelRegions.indicatePessimisticFixpoint();
587d9659bf6SJohannes Doerfert     return ChangeStatus::CHANGED;
588d9659bf6SJohannes Doerfert   }
589d9659bf6SJohannes Doerfert 
590d9659bf6SJohannes Doerfert   /// See AbstractState::indicateOptimisticFixpoint(...)
591d9659bf6SJohannes Doerfert   ChangeStatus indicateOptimisticFixpoint() override {
592d9659bf6SJohannes Doerfert     IsAtFixpoint = true;
593d61aac76SJohannes Doerfert     ReachingKernelEntries.indicateOptimisticFixpoint();
594d61aac76SJohannes Doerfert     SPMDCompatibilityTracker.indicateOptimisticFixpoint();
595d61aac76SJohannes Doerfert     ReachedKnownParallelRegions.indicateOptimisticFixpoint();
596d61aac76SJohannes Doerfert     ReachedUnknownParallelRegions.indicateOptimisticFixpoint();
597d9659bf6SJohannes Doerfert     return ChangeStatus::UNCHANGED;
598d9659bf6SJohannes Doerfert   }
599d9659bf6SJohannes Doerfert 
600d9659bf6SJohannes Doerfert   /// Return the assumed state
601d9659bf6SJohannes Doerfert   KernelInfoState &getAssumed() { return *this; }
602d9659bf6SJohannes Doerfert   const KernelInfoState &getAssumed() const { return *this; }
603d9659bf6SJohannes Doerfert 
604d9659bf6SJohannes Doerfert   bool operator==(const KernelInfoState &RHS) const {
605514c033dSJohannes Doerfert     if (SPMDCompatibilityTracker != RHS.SPMDCompatibilityTracker)
606514c033dSJohannes Doerfert       return false;
607d9659bf6SJohannes Doerfert     if (ReachedKnownParallelRegions != RHS.ReachedKnownParallelRegions)
608d9659bf6SJohannes Doerfert       return false;
609d9659bf6SJohannes Doerfert     if (ReachedUnknownParallelRegions != RHS.ReachedUnknownParallelRegions)
610d9659bf6SJohannes Doerfert       return false;
611ca662297SShilei Tian     if (ReachingKernelEntries != RHS.ReachingKernelEntries)
612ca662297SShilei Tian       return false;
613d9659bf6SJohannes Doerfert     return true;
614d9659bf6SJohannes Doerfert   }
615d9659bf6SJohannes Doerfert 
6166b9a3ec3SJoseph Huber   /// Returns true if this kernel contains any OpenMP parallel regions.
6176b9a3ec3SJoseph Huber   bool mayContainParallelRegion() {
6186b9a3ec3SJoseph Huber     return !ReachedKnownParallelRegions.empty() ||
6196b9a3ec3SJoseph Huber            !ReachedUnknownParallelRegions.empty();
6206b9a3ec3SJoseph Huber   }
6216b9a3ec3SJoseph Huber 
622d9659bf6SJohannes Doerfert   /// Return empty set as the best state of potential values.
623d9659bf6SJohannes Doerfert   static KernelInfoState getBestState() { return KernelInfoState(true); }
624d9659bf6SJohannes Doerfert 
625d9659bf6SJohannes Doerfert   static KernelInfoState getBestState(KernelInfoState &KIS) {
626d9659bf6SJohannes Doerfert     return getBestState();
627d9659bf6SJohannes Doerfert   }
628d9659bf6SJohannes Doerfert 
629d9659bf6SJohannes Doerfert   /// Return full set as the worst state of potential values.
630d9659bf6SJohannes Doerfert   static KernelInfoState getWorstState() { return KernelInfoState(false); }
631d9659bf6SJohannes Doerfert 
632d9659bf6SJohannes Doerfert   /// "Clamp" this state with \p KIS.
633d9659bf6SJohannes Doerfert   KernelInfoState operator^=(const KernelInfoState &KIS) {
634d9659bf6SJohannes Doerfert     // Do not merge two different _init and _deinit call sites.
635d9659bf6SJohannes Doerfert     if (KIS.KernelInitCB) {
636d9659bf6SJohannes Doerfert       if (KernelInitCB && KernelInitCB != KIS.KernelInitCB)
637e6e440aeSJohannes Doerfert         llvm_unreachable("Kernel that calls another kernel violates OpenMP-Opt "
638e6e440aeSJohannes Doerfert                          "assumptions.");
639d9659bf6SJohannes Doerfert       KernelInitCB = KIS.KernelInitCB;
640d9659bf6SJohannes Doerfert     }
641d9659bf6SJohannes Doerfert     if (KIS.KernelDeinitCB) {
642d9659bf6SJohannes Doerfert       if (KernelDeinitCB && KernelDeinitCB != KIS.KernelDeinitCB)
643e6e440aeSJohannes Doerfert         llvm_unreachable("Kernel that calls another kernel violates OpenMP-Opt "
644e6e440aeSJohannes Doerfert                          "assumptions.");
645d9659bf6SJohannes Doerfert       KernelDeinitCB = KIS.KernelDeinitCB;
646d9659bf6SJohannes Doerfert     }
647514c033dSJohannes Doerfert     SPMDCompatibilityTracker ^= KIS.SPMDCompatibilityTracker;
648d9659bf6SJohannes Doerfert     ReachedKnownParallelRegions ^= KIS.ReachedKnownParallelRegions;
649d9659bf6SJohannes Doerfert     ReachedUnknownParallelRegions ^= KIS.ReachedUnknownParallelRegions;
650d9659bf6SJohannes Doerfert     return *this;
651d9659bf6SJohannes Doerfert   }
652d9659bf6SJohannes Doerfert 
653d9659bf6SJohannes Doerfert   KernelInfoState operator&=(const KernelInfoState &KIS) {
654d9659bf6SJohannes Doerfert     return (*this ^= KIS);
655d9659bf6SJohannes Doerfert   }
656d9659bf6SJohannes Doerfert 
657d9659bf6SJohannes Doerfert   ///}
658d9659bf6SJohannes Doerfert };
659d9659bf6SJohannes Doerfert 
6608931add6SHamilton Tobon Mosquera /// Used to map the values physically (in the IR) stored in an offload
6618931add6SHamilton Tobon Mosquera /// array, to a vector in memory.
6628931add6SHamilton Tobon Mosquera struct OffloadArray {
6638931add6SHamilton Tobon Mosquera   /// Physical array (in the IR).
6648931add6SHamilton Tobon Mosquera   AllocaInst *Array = nullptr;
6658931add6SHamilton Tobon Mosquera   /// Mapped values.
6668931add6SHamilton Tobon Mosquera   SmallVector<Value *, 8> StoredValues;
6678931add6SHamilton Tobon Mosquera   /// Last stores made in the offload array.
6688931add6SHamilton Tobon Mosquera   SmallVector<StoreInst *, 8> LastAccesses;
6698931add6SHamilton Tobon Mosquera 
6708931add6SHamilton Tobon Mosquera   OffloadArray() = default;
6718931add6SHamilton Tobon Mosquera 
6728931add6SHamilton Tobon Mosquera   /// Initializes the OffloadArray with the values stored in \p Array before
6738931add6SHamilton Tobon Mosquera   /// instruction \p Before is reached. Returns false if the initialization
6748931add6SHamilton Tobon Mosquera   /// fails.
6758931add6SHamilton Tobon Mosquera   /// This MUST be used immediately after the construction of the object.
6768931add6SHamilton Tobon Mosquera   bool initialize(AllocaInst &Array, Instruction &Before) {
6778931add6SHamilton Tobon Mosquera     if (!Array.getAllocatedType()->isArrayTy())
6788931add6SHamilton Tobon Mosquera       return false;
6798931add6SHamilton Tobon Mosquera 
6808931add6SHamilton Tobon Mosquera     if (!getValues(Array, Before))
6818931add6SHamilton Tobon Mosquera       return false;
6828931add6SHamilton Tobon Mosquera 
6838931add6SHamilton Tobon Mosquera     this->Array = &Array;
6848931add6SHamilton Tobon Mosquera     return true;
6858931add6SHamilton Tobon Mosquera   }
6868931add6SHamilton Tobon Mosquera 
687da8bec47SJoseph Huber   static const unsigned DeviceIDArgNum = 1;
688da8bec47SJoseph Huber   static const unsigned BasePtrsArgNum = 3;
689da8bec47SJoseph Huber   static const unsigned PtrsArgNum = 4;
690da8bec47SJoseph Huber   static const unsigned SizesArgNum = 5;
6911d3d9b9cSHamilton Tobon Mosquera 
6928931add6SHamilton Tobon Mosquera private:
6938931add6SHamilton Tobon Mosquera   /// Traverses the BasicBlock where \p Array is, collecting the stores made to
6948931add6SHamilton Tobon Mosquera   /// \p Array, leaving StoredValues with the values stored before the
6958931add6SHamilton Tobon Mosquera   /// instruction \p Before is reached.
6968931add6SHamilton Tobon Mosquera   bool getValues(AllocaInst &Array, Instruction &Before) {
6978931add6SHamilton Tobon Mosquera     // Initialize container.
698d08d490aSJohannes Doerfert     const uint64_t NumValues = Array.getAllocatedType()->getArrayNumElements();
6998931add6SHamilton Tobon Mosquera     StoredValues.assign(NumValues, nullptr);
7008931add6SHamilton Tobon Mosquera     LastAccesses.assign(NumValues, nullptr);
7018931add6SHamilton Tobon Mosquera 
7028931add6SHamilton Tobon Mosquera     // TODO: This assumes the instruction \p Before is in the same
7038931add6SHamilton Tobon Mosquera     //  BasicBlock as Array. Make it general, for any control flow graph.
7048931add6SHamilton Tobon Mosquera     BasicBlock *BB = Array.getParent();
7058931add6SHamilton Tobon Mosquera     if (BB != Before.getParent())
7068931add6SHamilton Tobon Mosquera       return false;
7078931add6SHamilton Tobon Mosquera 
7088931add6SHamilton Tobon Mosquera     const DataLayout &DL = Array.getModule()->getDataLayout();
7098931add6SHamilton Tobon Mosquera     const unsigned int PointerSize = DL.getPointerSize();
7108931add6SHamilton Tobon Mosquera 
7118931add6SHamilton Tobon Mosquera     for (Instruction &I : *BB) {
7128931add6SHamilton Tobon Mosquera       if (&I == &Before)
7138931add6SHamilton Tobon Mosquera         break;
7148931add6SHamilton Tobon Mosquera 
7158931add6SHamilton Tobon Mosquera       if (!isa<StoreInst>(&I))
7168931add6SHamilton Tobon Mosquera         continue;
7178931add6SHamilton Tobon Mosquera 
7188931add6SHamilton Tobon Mosquera       auto *S = cast<StoreInst>(&I);
7198931add6SHamilton Tobon Mosquera       int64_t Offset = -1;
720d08d490aSJohannes Doerfert       auto *Dst =
721d08d490aSJohannes Doerfert           GetPointerBaseWithConstantOffset(S->getPointerOperand(), Offset, DL);
7228931add6SHamilton Tobon Mosquera       if (Dst == &Array) {
7238931add6SHamilton Tobon Mosquera         int64_t Idx = Offset / PointerSize;
7248931add6SHamilton Tobon Mosquera         StoredValues[Idx] = getUnderlyingObject(S->getValueOperand());
7258931add6SHamilton Tobon Mosquera         LastAccesses[Idx] = S;
7268931add6SHamilton Tobon Mosquera       }
7278931add6SHamilton Tobon Mosquera     }
7288931add6SHamilton Tobon Mosquera 
7298931add6SHamilton Tobon Mosquera     return isFilled();
7308931add6SHamilton Tobon Mosquera   }
7318931add6SHamilton Tobon Mosquera 
7328931add6SHamilton Tobon Mosquera   /// Returns true if all values in StoredValues and
7338931add6SHamilton Tobon Mosquera   /// LastAccesses are not nullptrs.
7348931add6SHamilton Tobon Mosquera   bool isFilled() {
7358931add6SHamilton Tobon Mosquera     const unsigned NumValues = StoredValues.size();
7368931add6SHamilton Tobon Mosquera     for (unsigned I = 0; I < NumValues; ++I) {
7378931add6SHamilton Tobon Mosquera       if (!StoredValues[I] || !LastAccesses[I])
7388931add6SHamilton Tobon Mosquera         return false;
7398931add6SHamilton Tobon Mosquera     }
7408931add6SHamilton Tobon Mosquera 
7418931add6SHamilton Tobon Mosquera     return true;
7428931add6SHamilton Tobon Mosquera   }
7438931add6SHamilton Tobon Mosquera };
7448931add6SHamilton Tobon Mosquera 
7457cfd267cSsstefan1 struct OpenMPOpt {
7467cfd267cSsstefan1 
7477cfd267cSsstefan1   using OptimizationRemarkGetter =
7487cfd267cSsstefan1       function_ref<OptimizationRemarkEmitter &(Function *)>;
7497cfd267cSsstefan1 
7507cfd267cSsstefan1   OpenMPOpt(SmallVectorImpl<Function *> &SCC, CallGraphUpdater &CGUpdater,
7517cfd267cSsstefan1             OptimizationRemarkGetter OREGetter,
752b8235d2bSsstefan1             OMPInformationCache &OMPInfoCache, Attributor &A)
75377b79d79SMehdi Amini       : M(*(*SCC.begin())->getParent()), SCC(SCC), CGUpdater(CGUpdater),
754b8235d2bSsstefan1         OREGetter(OREGetter), OMPInfoCache(OMPInfoCache), A(A) {}
7557cfd267cSsstefan1 
756a2281419SJoseph Huber   /// Check if any remarks are enabled for openmp-opt
757a2281419SJoseph Huber   bool remarksEnabled() {
758a2281419SJoseph Huber     auto &Ctx = M.getContext();
759a2281419SJoseph Huber     return Ctx.getDiagHandlerPtr()->isAnyRemarkEnabled(DEBUG_TYPE);
760a2281419SJoseph Huber   }
761a2281419SJoseph Huber 
7629548b74aSJohannes Doerfert   /// Run all OpenMP optimizations on the underlying SCC/ModuleSlice.
763b2ad63d3SJoseph Huber   bool run(bool IsModulePass) {
76454bd3751SJohannes Doerfert     if (SCC.empty())
76554bd3751SJohannes Doerfert       return false;
76654bd3751SJohannes Doerfert 
7679548b74aSJohannes Doerfert     bool Changed = false;
7689548b74aSJohannes Doerfert 
7699548b74aSJohannes Doerfert     LLVM_DEBUG(dbgs() << TAG << "Run on SCC with " << SCC.size()
77077b79d79SMehdi Amini                       << " functions in a slice with "
77177b79d79SMehdi Amini                       << OMPInfoCache.ModuleSlice.size() << " functions\n");
7729548b74aSJohannes Doerfert 
773b2ad63d3SJoseph Huber     if (IsModulePass) {
774d9659bf6SJohannes Doerfert       Changed |= runAttributor(IsModulePass);
77518283125SJoseph Huber 
7766fc51c9fSJoseph Huber       // Recollect uses, in case Attributor deleted any.
7776fc51c9fSJoseph Huber       OMPInfoCache.recollectUses();
7786fc51c9fSJoseph Huber 
779be2b5696SJohannes Doerfert       // TODO: This should be folded into buildCustomStateMachine.
780be2b5696SJohannes Doerfert       Changed |= rewriteDeviceCodeStateMachine();
781be2b5696SJohannes Doerfert 
782b2ad63d3SJoseph Huber       if (remarksEnabled())
783b2ad63d3SJoseph Huber         analysisGlobalization();
784b2ad63d3SJoseph Huber     } else {
785e8039ad4SJohannes Doerfert       if (PrintICVValues)
786e8039ad4SJohannes Doerfert         printICVs();
787e8039ad4SJohannes Doerfert       if (PrintOpenMPKernels)
788e8039ad4SJohannes Doerfert         printKernels();
789e8039ad4SJohannes Doerfert 
790d9659bf6SJohannes Doerfert       Changed |= runAttributor(IsModulePass);
791e8039ad4SJohannes Doerfert 
792e8039ad4SJohannes Doerfert       // Recollect uses, in case Attributor deleted any.
793e8039ad4SJohannes Doerfert       OMPInfoCache.recollectUses();
794e8039ad4SJohannes Doerfert 
795e8039ad4SJohannes Doerfert       Changed |= deleteParallelRegions();
796d9659bf6SJohannes Doerfert 
797496f8e5bSHamilton Tobon Mosquera       if (HideMemoryTransferLatency)
798496f8e5bSHamilton Tobon Mosquera         Changed |= hideMemTransfersLatency();
7993a6bfcf2SGiorgis Georgakoudis       Changed |= deduplicateRuntimeCalls();
8003a6bfcf2SGiorgis Georgakoudis       if (EnableParallelRegionMerging) {
8013a6bfcf2SGiorgis Georgakoudis         if (mergeParallelRegions()) {
8023a6bfcf2SGiorgis Georgakoudis           deduplicateRuntimeCalls();
8033a6bfcf2SGiorgis Georgakoudis           Changed = true;
8043a6bfcf2SGiorgis Georgakoudis         }
8053a6bfcf2SGiorgis Georgakoudis       }
806b2ad63d3SJoseph Huber     }
807e8039ad4SJohannes Doerfert 
808e8039ad4SJohannes Doerfert     return Changed;
809e8039ad4SJohannes Doerfert   }
810e8039ad4SJohannes Doerfert 
8110f426935Ssstefan1   /// Print initial ICV values for testing.
8120f426935Ssstefan1   /// FIXME: This should be done from the Attributor once it is added.
813e8039ad4SJohannes Doerfert   void printICVs() const {
814cb9cfa0dSsstefan1     InternalControlVar ICVs[] = {ICV_nthreads, ICV_active_levels, ICV_cancel,
815cb9cfa0dSsstefan1                                  ICV_proc_bind};
8160f426935Ssstefan1 
8170f426935Ssstefan1     for (Function *F : OMPInfoCache.ModuleSlice) {
8180f426935Ssstefan1       for (auto ICV : ICVs) {
8190f426935Ssstefan1         auto ICVInfo = OMPInfoCache.ICVs[ICV];
8202db182ffSJoseph Huber         auto Remark = [&](OptimizationRemarkAnalysis ORA) {
8212db182ffSJoseph Huber           return ORA << "OpenMP ICV " << ore::NV("OpenMPICV", ICVInfo.Name)
8220f426935Ssstefan1                      << " Value: "
8230f426935Ssstefan1                      << (ICVInfo.InitValue
82461cdaf66SSimon Pilgrim                              ? toString(ICVInfo.InitValue->getValue(), 10, true)
8250f426935Ssstefan1                              : "IMPLEMENTATION_DEFINED");
8260f426935Ssstefan1         };
8270f426935Ssstefan1 
8282db182ffSJoseph Huber         emitRemark<OptimizationRemarkAnalysis>(F, "OpenMPICVTracker", Remark);
8290f426935Ssstefan1       }
8300f426935Ssstefan1     }
8310f426935Ssstefan1   }
8320f426935Ssstefan1 
833e8039ad4SJohannes Doerfert   /// Print OpenMP GPU kernels for testing.
834e8039ad4SJohannes Doerfert   void printKernels() const {
835e8039ad4SJohannes Doerfert     for (Function *F : SCC) {
836e8039ad4SJohannes Doerfert       if (!OMPInfoCache.Kernels.count(F))
837e8039ad4SJohannes Doerfert         continue;
838b8235d2bSsstefan1 
8392db182ffSJoseph Huber       auto Remark = [&](OptimizationRemarkAnalysis ORA) {
8402db182ffSJoseph Huber         return ORA << "OpenMP GPU kernel "
841e8039ad4SJohannes Doerfert                    << ore::NV("OpenMPGPUKernel", F->getName()) << "\n";
842e8039ad4SJohannes Doerfert       };
843b8235d2bSsstefan1 
8442db182ffSJoseph Huber       emitRemark<OptimizationRemarkAnalysis>(F, "OpenMPGPU", Remark);
845e8039ad4SJohannes Doerfert     }
8469548b74aSJohannes Doerfert   }
8479548b74aSJohannes Doerfert 
8487cfd267cSsstefan1   /// Return the call if \p U is a callee use in a regular call. If \p RFI is
8497cfd267cSsstefan1   /// given it has to be the callee or a nullptr is returned.
8507cfd267cSsstefan1   static CallInst *getCallIfRegularCall(
8517cfd267cSsstefan1       Use &U, OMPInformationCache::RuntimeFunctionInfo *RFI = nullptr) {
8527cfd267cSsstefan1     CallInst *CI = dyn_cast<CallInst>(U.getUser());
8537cfd267cSsstefan1     if (CI && CI->isCallee(&U) && !CI->hasOperandBundles() &&
854c4b1fe05SJohannes Doerfert         (!RFI ||
855c4b1fe05SJohannes Doerfert          (RFI->Declaration && CI->getCalledFunction() == RFI->Declaration)))
8567cfd267cSsstefan1       return CI;
8577cfd267cSsstefan1     return nullptr;
8587cfd267cSsstefan1   }
8597cfd267cSsstefan1 
8607cfd267cSsstefan1   /// Return the call if \p V is a regular call. If \p RFI is given it has to be
8617cfd267cSsstefan1   /// the callee or a nullptr is returned.
8627cfd267cSsstefan1   static CallInst *getCallIfRegularCall(
8637cfd267cSsstefan1       Value &V, OMPInformationCache::RuntimeFunctionInfo *RFI = nullptr) {
8647cfd267cSsstefan1     CallInst *CI = dyn_cast<CallInst>(&V);
8657cfd267cSsstefan1     if (CI && !CI->hasOperandBundles() &&
866c4b1fe05SJohannes Doerfert         (!RFI ||
867c4b1fe05SJohannes Doerfert          (RFI->Declaration && CI->getCalledFunction() == RFI->Declaration)))
8687cfd267cSsstefan1       return CI;
8697cfd267cSsstefan1     return nullptr;
8707cfd267cSsstefan1   }
8717cfd267cSsstefan1 
8729548b74aSJohannes Doerfert private:
8733a6bfcf2SGiorgis Georgakoudis   /// Merge parallel regions when it is safe.
8743a6bfcf2SGiorgis Georgakoudis   bool mergeParallelRegions() {
8753a6bfcf2SGiorgis Georgakoudis     const unsigned CallbackCalleeOperand = 2;
8763a6bfcf2SGiorgis Georgakoudis     const unsigned CallbackFirstArgOperand = 3;
8773a6bfcf2SGiorgis Georgakoudis     using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
8783a6bfcf2SGiorgis Georgakoudis 
8793a6bfcf2SGiorgis Georgakoudis     // Check if there are any __kmpc_fork_call calls to merge.
8803a6bfcf2SGiorgis Georgakoudis     OMPInformationCache::RuntimeFunctionInfo &RFI =
8813a6bfcf2SGiorgis Georgakoudis         OMPInfoCache.RFIs[OMPRTL___kmpc_fork_call];
8823a6bfcf2SGiorgis Georgakoudis 
8833a6bfcf2SGiorgis Georgakoudis     if (!RFI.Declaration)
8843a6bfcf2SGiorgis Georgakoudis       return false;
8853a6bfcf2SGiorgis Georgakoudis 
88697517055SGiorgis Georgakoudis     // Unmergable calls that prevent merging a parallel region.
88797517055SGiorgis Georgakoudis     OMPInformationCache::RuntimeFunctionInfo UnmergableCallsInfo[] = {
88897517055SGiorgis Georgakoudis         OMPInfoCache.RFIs[OMPRTL___kmpc_push_proc_bind],
88997517055SGiorgis Georgakoudis         OMPInfoCache.RFIs[OMPRTL___kmpc_push_num_threads],
89097517055SGiorgis Georgakoudis     };
8913a6bfcf2SGiorgis Georgakoudis 
8923a6bfcf2SGiorgis Georgakoudis     bool Changed = false;
8933a6bfcf2SGiorgis Georgakoudis     LoopInfo *LI = nullptr;
8943a6bfcf2SGiorgis Georgakoudis     DominatorTree *DT = nullptr;
8953a6bfcf2SGiorgis Georgakoudis 
8963a6bfcf2SGiorgis Georgakoudis     SmallDenseMap<BasicBlock *, SmallPtrSet<Instruction *, 4>> BB2PRMap;
8973a6bfcf2SGiorgis Georgakoudis 
8983a6bfcf2SGiorgis Georgakoudis     BasicBlock *StartBB = nullptr, *EndBB = nullptr;
8993a6bfcf2SGiorgis Georgakoudis     auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
9003a6bfcf2SGiorgis Georgakoudis                          BasicBlock &ContinuationIP) {
9013a6bfcf2SGiorgis Georgakoudis       BasicBlock *CGStartBB = CodeGenIP.getBlock();
9023a6bfcf2SGiorgis Georgakoudis       BasicBlock *CGEndBB =
9033a6bfcf2SGiorgis Georgakoudis           SplitBlock(CGStartBB, &*CodeGenIP.getPoint(), DT, LI);
9043a6bfcf2SGiorgis Georgakoudis       assert(StartBB != nullptr && "StartBB should not be null");
9053a6bfcf2SGiorgis Georgakoudis       CGStartBB->getTerminator()->setSuccessor(0, StartBB);
9063a6bfcf2SGiorgis Georgakoudis       assert(EndBB != nullptr && "EndBB should not be null");
9073a6bfcf2SGiorgis Georgakoudis       EndBB->getTerminator()->setSuccessor(0, CGEndBB);
9083a6bfcf2SGiorgis Georgakoudis     };
9093a6bfcf2SGiorgis Georgakoudis 
910240dd924SAlex Zinenko     auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, Value &,
911240dd924SAlex Zinenko                       Value &Inner, Value *&ReplacementValue) -> InsertPointTy {
912240dd924SAlex Zinenko       ReplacementValue = &Inner;
9133a6bfcf2SGiorgis Georgakoudis       return CodeGenIP;
9143a6bfcf2SGiorgis Georgakoudis     };
9153a6bfcf2SGiorgis Georgakoudis 
9163a6bfcf2SGiorgis Georgakoudis     auto FiniCB = [&](InsertPointTy CodeGenIP) {};
9173a6bfcf2SGiorgis Georgakoudis 
91897517055SGiorgis Georgakoudis     /// Create a sequential execution region within a merged parallel region,
91997517055SGiorgis Georgakoudis     /// encapsulated in a master construct with a barrier for synchronization.
92097517055SGiorgis Georgakoudis     auto CreateSequentialRegion = [&](Function *OuterFn,
92197517055SGiorgis Georgakoudis                                       BasicBlock *OuterPredBB,
92297517055SGiorgis Georgakoudis                                       Instruction *SeqStartI,
92397517055SGiorgis Georgakoudis                                       Instruction *SeqEndI) {
92497517055SGiorgis Georgakoudis       // Isolate the instructions of the sequential region to a separate
92597517055SGiorgis Georgakoudis       // block.
92697517055SGiorgis Georgakoudis       BasicBlock *ParentBB = SeqStartI->getParent();
92797517055SGiorgis Georgakoudis       BasicBlock *SeqEndBB =
92897517055SGiorgis Georgakoudis           SplitBlock(ParentBB, SeqEndI->getNextNode(), DT, LI);
92997517055SGiorgis Georgakoudis       BasicBlock *SeqAfterBB =
93097517055SGiorgis Georgakoudis           SplitBlock(SeqEndBB, &*SeqEndBB->getFirstInsertionPt(), DT, LI);
93197517055SGiorgis Georgakoudis       BasicBlock *SeqStartBB =
93297517055SGiorgis Georgakoudis           SplitBlock(ParentBB, SeqStartI, DT, LI, nullptr, "seq.par.merged");
93397517055SGiorgis Georgakoudis 
93497517055SGiorgis Georgakoudis       assert(ParentBB->getUniqueSuccessor() == SeqStartBB &&
93597517055SGiorgis Georgakoudis              "Expected a different CFG");
93697517055SGiorgis Georgakoudis       const DebugLoc DL = ParentBB->getTerminator()->getDebugLoc();
93797517055SGiorgis Georgakoudis       ParentBB->getTerminator()->eraseFromParent();
93897517055SGiorgis Georgakoudis 
93997517055SGiorgis Georgakoudis       auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
94097517055SGiorgis Georgakoudis                            BasicBlock &ContinuationIP) {
94197517055SGiorgis Georgakoudis         BasicBlock *CGStartBB = CodeGenIP.getBlock();
94297517055SGiorgis Georgakoudis         BasicBlock *CGEndBB =
94397517055SGiorgis Georgakoudis             SplitBlock(CGStartBB, &*CodeGenIP.getPoint(), DT, LI);
94497517055SGiorgis Georgakoudis         assert(SeqStartBB != nullptr && "SeqStartBB should not be null");
94597517055SGiorgis Georgakoudis         CGStartBB->getTerminator()->setSuccessor(0, SeqStartBB);
94697517055SGiorgis Georgakoudis         assert(SeqEndBB != nullptr && "SeqEndBB should not be null");
94797517055SGiorgis Georgakoudis         SeqEndBB->getTerminator()->setSuccessor(0, CGEndBB);
94897517055SGiorgis Georgakoudis       };
94997517055SGiorgis Georgakoudis       auto FiniCB = [&](InsertPointTy CodeGenIP) {};
95097517055SGiorgis Georgakoudis 
95197517055SGiorgis Georgakoudis       // Find outputs from the sequential region to outside users and
95297517055SGiorgis Georgakoudis       // broadcast their values to them.
95397517055SGiorgis Georgakoudis       for (Instruction &I : *SeqStartBB) {
95497517055SGiorgis Georgakoudis         SmallPtrSet<Instruction *, 4> OutsideUsers;
95597517055SGiorgis Georgakoudis         for (User *Usr : I.users()) {
95697517055SGiorgis Georgakoudis           Instruction &UsrI = *cast<Instruction>(Usr);
95797517055SGiorgis Georgakoudis           // Ignore outputs to LT intrinsics, code extraction for the merged
95897517055SGiorgis Georgakoudis           // parallel region will fix them.
95997517055SGiorgis Georgakoudis           if (UsrI.isLifetimeStartOrEnd())
96097517055SGiorgis Georgakoudis             continue;
96197517055SGiorgis Georgakoudis 
96297517055SGiorgis Georgakoudis           if (UsrI.getParent() != SeqStartBB)
96397517055SGiorgis Georgakoudis             OutsideUsers.insert(&UsrI);
96497517055SGiorgis Georgakoudis         }
96597517055SGiorgis Georgakoudis 
96697517055SGiorgis Georgakoudis         if (OutsideUsers.empty())
96797517055SGiorgis Georgakoudis           continue;
96897517055SGiorgis Georgakoudis 
96997517055SGiorgis Georgakoudis         // Emit an alloca in the outer region to store the broadcasted
97097517055SGiorgis Georgakoudis         // value.
97197517055SGiorgis Georgakoudis         const DataLayout &DL = M.getDataLayout();
97297517055SGiorgis Georgakoudis         AllocaInst *AllocaI = new AllocaInst(
97397517055SGiorgis Georgakoudis             I.getType(), DL.getAllocaAddrSpace(), nullptr,
97497517055SGiorgis Georgakoudis             I.getName() + ".seq.output.alloc", &OuterFn->front().front());
97597517055SGiorgis Georgakoudis 
97697517055SGiorgis Georgakoudis         // Emit a store instruction in the sequential BB to update the
97797517055SGiorgis Georgakoudis         // value.
97897517055SGiorgis Georgakoudis         new StoreInst(&I, AllocaI, SeqStartBB->getTerminator());
97997517055SGiorgis Georgakoudis 
98097517055SGiorgis Georgakoudis         // Emit a load instruction and replace the use of the output value
98197517055SGiorgis Georgakoudis         // with it.
98297517055SGiorgis Georgakoudis         for (Instruction *UsrI : OutsideUsers) {
9835b70c12fSJohannes Doerfert           LoadInst *LoadI = new LoadInst(
9845b70c12fSJohannes Doerfert               I.getType(), AllocaI, I.getName() + ".seq.output.load", UsrI);
98597517055SGiorgis Georgakoudis           UsrI->replaceUsesOfWith(&I, LoadI);
98697517055SGiorgis Georgakoudis         }
98797517055SGiorgis Georgakoudis       }
98897517055SGiorgis Georgakoudis 
98997517055SGiorgis Georgakoudis       OpenMPIRBuilder::LocationDescription Loc(
99097517055SGiorgis Georgakoudis           InsertPointTy(ParentBB, ParentBB->end()), DL);
99197517055SGiorgis Georgakoudis       InsertPointTy SeqAfterIP =
99297517055SGiorgis Georgakoudis           OMPInfoCache.OMPBuilder.createMaster(Loc, BodyGenCB, FiniCB);
99397517055SGiorgis Georgakoudis 
99497517055SGiorgis Georgakoudis       OMPInfoCache.OMPBuilder.createBarrier(SeqAfterIP, OMPD_parallel);
99597517055SGiorgis Georgakoudis 
99697517055SGiorgis Georgakoudis       BranchInst::Create(SeqAfterBB, SeqAfterIP.getBlock());
99797517055SGiorgis Georgakoudis 
99897517055SGiorgis Georgakoudis       LLVM_DEBUG(dbgs() << TAG << "After sequential inlining " << *OuterFn
99997517055SGiorgis Georgakoudis                         << "\n");
100097517055SGiorgis Georgakoudis     };
100197517055SGiorgis Georgakoudis 
10023a6bfcf2SGiorgis Georgakoudis     // Helper to merge the __kmpc_fork_call calls in MergableCIs. They are all
10033a6bfcf2SGiorgis Georgakoudis     // contained in BB and only separated by instructions that can be
10043a6bfcf2SGiorgis Georgakoudis     // redundantly executed in parallel. The block BB is split before the first
10053a6bfcf2SGiorgis Georgakoudis     // call (in MergableCIs) and after the last so the entire region we merge
10063a6bfcf2SGiorgis Georgakoudis     // into a single parallel region is contained in a single basic block
10073a6bfcf2SGiorgis Georgakoudis     // without any other instructions. We use the OpenMPIRBuilder to outline
10083a6bfcf2SGiorgis Georgakoudis     // that block and call the resulting function via __kmpc_fork_call.
10093a6bfcf2SGiorgis Georgakoudis     auto Merge = [&](SmallVectorImpl<CallInst *> &MergableCIs, BasicBlock *BB) {
10103a6bfcf2SGiorgis Georgakoudis       // TODO: Change the interface to allow single CIs expanded, e.g, to
10113a6bfcf2SGiorgis Georgakoudis       // include an outer loop.
10123a6bfcf2SGiorgis Georgakoudis       assert(MergableCIs.size() > 1 && "Assumed multiple mergable CIs");
10133a6bfcf2SGiorgis Georgakoudis 
10143a6bfcf2SGiorgis Georgakoudis       auto Remark = [&](OptimizationRemark OR) {
1015eef6601bSJoseph Huber         OR << "Parallel region merged with parallel region"
1016eef6601bSJoseph Huber            << (MergableCIs.size() > 2 ? "s" : "") << " at ";
101723b0ab2aSKazu Hirata         for (auto *CI : llvm::drop_begin(MergableCIs)) {
10183a6bfcf2SGiorgis Georgakoudis           OR << ore::NV("OpenMPParallelMerge", CI->getDebugLoc());
10193a6bfcf2SGiorgis Georgakoudis           if (CI != MergableCIs.back())
10203a6bfcf2SGiorgis Georgakoudis             OR << ", ";
10213a6bfcf2SGiorgis Georgakoudis         }
1022eef6601bSJoseph Huber         return OR << ".";
10233a6bfcf2SGiorgis Georgakoudis       };
10243a6bfcf2SGiorgis Georgakoudis 
10252c31d5ebSJoseph Huber       emitRemark<OptimizationRemark>(MergableCIs.front(), "OMP150", Remark);
10263a6bfcf2SGiorgis Georgakoudis 
10273a6bfcf2SGiorgis Georgakoudis       Function *OriginalFn = BB->getParent();
10283a6bfcf2SGiorgis Georgakoudis       LLVM_DEBUG(dbgs() << TAG << "Merge " << MergableCIs.size()
10293a6bfcf2SGiorgis Georgakoudis                         << " parallel regions in " << OriginalFn->getName()
10303a6bfcf2SGiorgis Georgakoudis                         << "\n");
10313a6bfcf2SGiorgis Georgakoudis 
10323a6bfcf2SGiorgis Georgakoudis       // Isolate the calls to merge in a separate block.
10333a6bfcf2SGiorgis Georgakoudis       EndBB = SplitBlock(BB, MergableCIs.back()->getNextNode(), DT, LI);
10343a6bfcf2SGiorgis Georgakoudis       BasicBlock *AfterBB =
10353a6bfcf2SGiorgis Georgakoudis           SplitBlock(EndBB, &*EndBB->getFirstInsertionPt(), DT, LI);
10363a6bfcf2SGiorgis Georgakoudis       StartBB = SplitBlock(BB, MergableCIs.front(), DT, LI, nullptr,
10373a6bfcf2SGiorgis Georgakoudis                            "omp.par.merged");
10383a6bfcf2SGiorgis Georgakoudis 
10393a6bfcf2SGiorgis Georgakoudis       assert(BB->getUniqueSuccessor() == StartBB && "Expected a different CFG");
10403a6bfcf2SGiorgis Georgakoudis       const DebugLoc DL = BB->getTerminator()->getDebugLoc();
10413a6bfcf2SGiorgis Georgakoudis       BB->getTerminator()->eraseFromParent();
10423a6bfcf2SGiorgis Georgakoudis 
104397517055SGiorgis Georgakoudis       // Create sequential regions for sequential instructions that are
104497517055SGiorgis Georgakoudis       // in-between mergable parallel regions.
104597517055SGiorgis Georgakoudis       for (auto *It = MergableCIs.begin(), *End = MergableCIs.end() - 1;
104697517055SGiorgis Georgakoudis            It != End; ++It) {
104797517055SGiorgis Georgakoudis         Instruction *ForkCI = *It;
104897517055SGiorgis Georgakoudis         Instruction *NextForkCI = *(It + 1);
104997517055SGiorgis Georgakoudis 
105097517055SGiorgis Georgakoudis         // Continue if there are not in-between instructions.
105197517055SGiorgis Georgakoudis         if (ForkCI->getNextNode() == NextForkCI)
105297517055SGiorgis Georgakoudis           continue;
105397517055SGiorgis Georgakoudis 
105497517055SGiorgis Georgakoudis         CreateSequentialRegion(OriginalFn, BB, ForkCI->getNextNode(),
105597517055SGiorgis Georgakoudis                                NextForkCI->getPrevNode());
105697517055SGiorgis Georgakoudis       }
105797517055SGiorgis Georgakoudis 
10583a6bfcf2SGiorgis Georgakoudis       OpenMPIRBuilder::LocationDescription Loc(InsertPointTy(BB, BB->end()),
10593a6bfcf2SGiorgis Georgakoudis                                                DL);
10603a6bfcf2SGiorgis Georgakoudis       IRBuilder<>::InsertPoint AllocaIP(
10613a6bfcf2SGiorgis Georgakoudis           &OriginalFn->getEntryBlock(),
10623a6bfcf2SGiorgis Georgakoudis           OriginalFn->getEntryBlock().getFirstInsertionPt());
10633a6bfcf2SGiorgis Georgakoudis       // Create the merged parallel region with default proc binding, to
10643a6bfcf2SGiorgis Georgakoudis       // avoid overriding binding settings, and without explicit cancellation.
1065e5dba2d7SMichael Kruse       InsertPointTy AfterIP = OMPInfoCache.OMPBuilder.createParallel(
10663a6bfcf2SGiorgis Georgakoudis           Loc, AllocaIP, BodyGenCB, PrivCB, FiniCB, nullptr, nullptr,
10673a6bfcf2SGiorgis Georgakoudis           OMP_PROC_BIND_default, /* IsCancellable */ false);
10683a6bfcf2SGiorgis Georgakoudis       BranchInst::Create(AfterBB, AfterIP.getBlock());
10693a6bfcf2SGiorgis Georgakoudis 
10703a6bfcf2SGiorgis Georgakoudis       // Perform the actual outlining.
1071b1191206SMichael Kruse       OMPInfoCache.OMPBuilder.finalize(OriginalFn,
1072b1191206SMichael Kruse                                        /* AllowExtractorSinking */ true);
10733a6bfcf2SGiorgis Georgakoudis 
10743a6bfcf2SGiorgis Georgakoudis       Function *OutlinedFn = MergableCIs.front()->getCaller();
10753a6bfcf2SGiorgis Georgakoudis 
10763a6bfcf2SGiorgis Georgakoudis       // Replace the __kmpc_fork_call calls with direct calls to the outlined
10773a6bfcf2SGiorgis Georgakoudis       // callbacks.
10783a6bfcf2SGiorgis Georgakoudis       SmallVector<Value *, 8> Args;
10793a6bfcf2SGiorgis Georgakoudis       for (auto *CI : MergableCIs) {
10803a6bfcf2SGiorgis Georgakoudis         Value *Callee =
10813a6bfcf2SGiorgis Georgakoudis             CI->getArgOperand(CallbackCalleeOperand)->stripPointerCasts();
10823a6bfcf2SGiorgis Georgakoudis         FunctionType *FT =
10833a6bfcf2SGiorgis Georgakoudis             cast<FunctionType>(Callee->getType()->getPointerElementType());
10843a6bfcf2SGiorgis Georgakoudis         Args.clear();
10853a6bfcf2SGiorgis Georgakoudis         Args.push_back(OutlinedFn->getArg(0));
10863a6bfcf2SGiorgis Georgakoudis         Args.push_back(OutlinedFn->getArg(1));
10874f0225f6SKazu Hirata         for (unsigned U = CallbackFirstArgOperand, E = CI->arg_size(); U < E;
10884f0225f6SKazu Hirata              ++U)
10893a6bfcf2SGiorgis Georgakoudis           Args.push_back(CI->getArgOperand(U));
10903a6bfcf2SGiorgis Georgakoudis 
10913a6bfcf2SGiorgis Georgakoudis         CallInst *NewCI = CallInst::Create(FT, Callee, Args, "", CI);
10923a6bfcf2SGiorgis Georgakoudis         if (CI->getDebugLoc())
10933a6bfcf2SGiorgis Georgakoudis           NewCI->setDebugLoc(CI->getDebugLoc());
10943a6bfcf2SGiorgis Georgakoudis 
10953a6bfcf2SGiorgis Georgakoudis         // Forward parameter attributes from the callback to the callee.
10964f0225f6SKazu Hirata         for (unsigned U = CallbackFirstArgOperand, E = CI->arg_size(); U < E;
10974f0225f6SKazu Hirata              ++U)
109880ea2bb5SArthur Eubanks           for (const Attribute &A : CI->getAttributes().getParamAttrs(U))
10993a6bfcf2SGiorgis Georgakoudis             NewCI->addParamAttr(
11003a6bfcf2SGiorgis Georgakoudis                 U - (CallbackFirstArgOperand - CallbackCalleeOperand), A);
11013a6bfcf2SGiorgis Georgakoudis 
11023a6bfcf2SGiorgis Georgakoudis         // Emit an explicit barrier to replace the implicit fork-join barrier.
11033a6bfcf2SGiorgis Georgakoudis         if (CI != MergableCIs.back()) {
11043a6bfcf2SGiorgis Georgakoudis           // TODO: Remove barrier if the merged parallel region includes the
11053a6bfcf2SGiorgis Georgakoudis           // 'nowait' clause.
1106e5dba2d7SMichael Kruse           OMPInfoCache.OMPBuilder.createBarrier(
11073a6bfcf2SGiorgis Georgakoudis               InsertPointTy(NewCI->getParent(),
11083a6bfcf2SGiorgis Georgakoudis                             NewCI->getNextNode()->getIterator()),
11093a6bfcf2SGiorgis Georgakoudis               OMPD_parallel);
11103a6bfcf2SGiorgis Georgakoudis         }
11113a6bfcf2SGiorgis Georgakoudis 
11123a6bfcf2SGiorgis Georgakoudis         CI->eraseFromParent();
11133a6bfcf2SGiorgis Georgakoudis       }
11143a6bfcf2SGiorgis Georgakoudis 
11153a6bfcf2SGiorgis Georgakoudis       assert(OutlinedFn != OriginalFn && "Outlining failed");
11167fea561eSArthur Eubanks       CGUpdater.registerOutlinedFunction(*OriginalFn, *OutlinedFn);
11173a6bfcf2SGiorgis Georgakoudis       CGUpdater.reanalyzeFunction(*OriginalFn);
11183a6bfcf2SGiorgis Georgakoudis 
11193a6bfcf2SGiorgis Georgakoudis       NumOpenMPParallelRegionsMerged += MergableCIs.size();
11203a6bfcf2SGiorgis Georgakoudis 
11213a6bfcf2SGiorgis Georgakoudis       return true;
11223a6bfcf2SGiorgis Georgakoudis     };
11233a6bfcf2SGiorgis Georgakoudis 
11243a6bfcf2SGiorgis Georgakoudis     // Helper function that identifes sequences of
11253a6bfcf2SGiorgis Georgakoudis     // __kmpc_fork_call uses in a basic block.
11263a6bfcf2SGiorgis Georgakoudis     auto DetectPRsCB = [&](Use &U, Function &F) {
11273a6bfcf2SGiorgis Georgakoudis       CallInst *CI = getCallIfRegularCall(U, &RFI);
11283a6bfcf2SGiorgis Georgakoudis       BB2PRMap[CI->getParent()].insert(CI);
11293a6bfcf2SGiorgis Georgakoudis 
11303a6bfcf2SGiorgis Georgakoudis       return false;
11313a6bfcf2SGiorgis Georgakoudis     };
11323a6bfcf2SGiorgis Georgakoudis 
11333a6bfcf2SGiorgis Georgakoudis     BB2PRMap.clear();
11343a6bfcf2SGiorgis Georgakoudis     RFI.foreachUse(SCC, DetectPRsCB);
11353a6bfcf2SGiorgis Georgakoudis     SmallVector<SmallVector<CallInst *, 4>, 4> MergableCIsVector;
11363a6bfcf2SGiorgis Georgakoudis     // Find mergable parallel regions within a basic block that are
11373a6bfcf2SGiorgis Georgakoudis     // safe to merge, that is any in-between instructions can safely
11383a6bfcf2SGiorgis Georgakoudis     // execute in parallel after merging.
11393a6bfcf2SGiorgis Georgakoudis     // TODO: support merging across basic-blocks.
11403a6bfcf2SGiorgis Georgakoudis     for (auto &It : BB2PRMap) {
11413a6bfcf2SGiorgis Georgakoudis       auto &CIs = It.getSecond();
11423a6bfcf2SGiorgis Georgakoudis       if (CIs.size() < 2)
11433a6bfcf2SGiorgis Georgakoudis         continue;
11443a6bfcf2SGiorgis Georgakoudis 
11453a6bfcf2SGiorgis Georgakoudis       BasicBlock *BB = It.getFirst();
11463a6bfcf2SGiorgis Georgakoudis       SmallVector<CallInst *, 4> MergableCIs;
11473a6bfcf2SGiorgis Georgakoudis 
114897517055SGiorgis Georgakoudis       /// Returns true if the instruction is mergable, false otherwise.
114997517055SGiorgis Georgakoudis       /// A terminator instruction is unmergable by definition since merging
115097517055SGiorgis Georgakoudis       /// works within a BB. Instructions before the mergable region are
115197517055SGiorgis Georgakoudis       /// mergable if they are not calls to OpenMP runtime functions that may
115297517055SGiorgis Georgakoudis       /// set different execution parameters for subsequent parallel regions.
115397517055SGiorgis Georgakoudis       /// Instructions in-between parallel regions are mergable if they are not
115497517055SGiorgis Georgakoudis       /// calls to any non-intrinsic function since that may call a non-mergable
115597517055SGiorgis Georgakoudis       /// OpenMP runtime function.
115697517055SGiorgis Georgakoudis       auto IsMergable = [&](Instruction &I, bool IsBeforeMergableRegion) {
115797517055SGiorgis Georgakoudis         // We do not merge across BBs, hence return false (unmergable) if the
115897517055SGiorgis Georgakoudis         // instruction is a terminator.
115997517055SGiorgis Georgakoudis         if (I.isTerminator())
116097517055SGiorgis Georgakoudis           return false;
116197517055SGiorgis Georgakoudis 
116297517055SGiorgis Georgakoudis         if (!isa<CallInst>(&I))
116397517055SGiorgis Georgakoudis           return true;
116497517055SGiorgis Georgakoudis 
116597517055SGiorgis Georgakoudis         CallInst *CI = cast<CallInst>(&I);
116697517055SGiorgis Georgakoudis         if (IsBeforeMergableRegion) {
116797517055SGiorgis Georgakoudis           Function *CalledFunction = CI->getCalledFunction();
116897517055SGiorgis Georgakoudis           if (!CalledFunction)
116997517055SGiorgis Georgakoudis             return false;
117097517055SGiorgis Georgakoudis           // Return false (unmergable) if the call before the parallel
117197517055SGiorgis Georgakoudis           // region calls an explicit affinity (proc_bind) or number of
117297517055SGiorgis Georgakoudis           // threads (num_threads) compiler-generated function. Those settings
117397517055SGiorgis Georgakoudis           // may be incompatible with following parallel regions.
117497517055SGiorgis Georgakoudis           // TODO: ICV tracking to detect compatibility.
117597517055SGiorgis Georgakoudis           for (const auto &RFI : UnmergableCallsInfo) {
117697517055SGiorgis Georgakoudis             if (CalledFunction == RFI.Declaration)
117797517055SGiorgis Georgakoudis               return false;
117897517055SGiorgis Georgakoudis           }
117997517055SGiorgis Georgakoudis         } else {
118097517055SGiorgis Georgakoudis           // Return false (unmergable) if there is a call instruction
118197517055SGiorgis Georgakoudis           // in-between parallel regions when it is not an intrinsic. It
118297517055SGiorgis Georgakoudis           // may call an unmergable OpenMP runtime function in its callpath.
118397517055SGiorgis Georgakoudis           // TODO: Keep track of possible OpenMP calls in the callpath.
118497517055SGiorgis Georgakoudis           if (!isa<IntrinsicInst>(CI))
118597517055SGiorgis Georgakoudis             return false;
118697517055SGiorgis Georgakoudis         }
118797517055SGiorgis Georgakoudis 
118897517055SGiorgis Georgakoudis         return true;
118997517055SGiorgis Georgakoudis       };
11903a6bfcf2SGiorgis Georgakoudis       // Find maximal number of parallel region CIs that are safe to merge.
119197517055SGiorgis Georgakoudis       for (auto It = BB->begin(), End = BB->end(); It != End;) {
119297517055SGiorgis Georgakoudis         Instruction &I = *It;
119397517055SGiorgis Georgakoudis         ++It;
119497517055SGiorgis Georgakoudis 
11953a6bfcf2SGiorgis Georgakoudis         if (CIs.count(&I)) {
11963a6bfcf2SGiorgis Georgakoudis           MergableCIs.push_back(cast<CallInst>(&I));
11973a6bfcf2SGiorgis Georgakoudis           continue;
11983a6bfcf2SGiorgis Georgakoudis         }
11993a6bfcf2SGiorgis Georgakoudis 
120097517055SGiorgis Georgakoudis         // Continue expanding if the instruction is mergable.
120197517055SGiorgis Georgakoudis         if (IsMergable(I, MergableCIs.empty()))
12023a6bfcf2SGiorgis Georgakoudis           continue;
12033a6bfcf2SGiorgis Georgakoudis 
120497517055SGiorgis Georgakoudis         // Forward the instruction iterator to skip the next parallel region
120597517055SGiorgis Georgakoudis         // since there is an unmergable instruction which can affect it.
120697517055SGiorgis Georgakoudis         for (; It != End; ++It) {
120797517055SGiorgis Georgakoudis           Instruction &SkipI = *It;
120897517055SGiorgis Georgakoudis           if (CIs.count(&SkipI)) {
120997517055SGiorgis Georgakoudis             LLVM_DEBUG(dbgs() << TAG << "Skip parallel region " << SkipI
121097517055SGiorgis Georgakoudis                               << " due to " << I << "\n");
121197517055SGiorgis Georgakoudis             ++It;
121297517055SGiorgis Georgakoudis             break;
121397517055SGiorgis Georgakoudis           }
121497517055SGiorgis Georgakoudis         }
121597517055SGiorgis Georgakoudis 
121697517055SGiorgis Georgakoudis         // Store mergable regions found.
12173a6bfcf2SGiorgis Georgakoudis         if (MergableCIs.size() > 1) {
12183a6bfcf2SGiorgis Georgakoudis           MergableCIsVector.push_back(MergableCIs);
12193a6bfcf2SGiorgis Georgakoudis           LLVM_DEBUG(dbgs() << TAG << "Found " << MergableCIs.size()
12203a6bfcf2SGiorgis Georgakoudis                             << " parallel regions in block " << BB->getName()
12213a6bfcf2SGiorgis Georgakoudis                             << " of function " << BB->getParent()->getName()
12223a6bfcf2SGiorgis Georgakoudis                             << "\n";);
12233a6bfcf2SGiorgis Georgakoudis         }
12243a6bfcf2SGiorgis Georgakoudis 
12253a6bfcf2SGiorgis Georgakoudis         MergableCIs.clear();
12263a6bfcf2SGiorgis Georgakoudis       }
12273a6bfcf2SGiorgis Georgakoudis 
12283a6bfcf2SGiorgis Georgakoudis       if (!MergableCIsVector.empty()) {
12293a6bfcf2SGiorgis Georgakoudis         Changed = true;
12303a6bfcf2SGiorgis Georgakoudis 
12313a6bfcf2SGiorgis Georgakoudis         for (auto &MergableCIs : MergableCIsVector)
12323a6bfcf2SGiorgis Georgakoudis           Merge(MergableCIs, BB);
1233b2ad63d3SJoseph Huber         MergableCIsVector.clear();
12343a6bfcf2SGiorgis Georgakoudis       }
12353a6bfcf2SGiorgis Georgakoudis     }
12363a6bfcf2SGiorgis Georgakoudis 
12373a6bfcf2SGiorgis Georgakoudis     if (Changed) {
123897517055SGiorgis Georgakoudis       /// Re-collect use for fork calls, emitted barrier calls, and
123997517055SGiorgis Georgakoudis       /// any emitted master/end_master calls.
124097517055SGiorgis Georgakoudis       OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_fork_call);
124197517055SGiorgis Georgakoudis       OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_barrier);
124297517055SGiorgis Georgakoudis       OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_master);
124397517055SGiorgis Georgakoudis       OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_end_master);
12443a6bfcf2SGiorgis Georgakoudis     }
12453a6bfcf2SGiorgis Georgakoudis 
12463a6bfcf2SGiorgis Georgakoudis     return Changed;
12473a6bfcf2SGiorgis Georgakoudis   }
12483a6bfcf2SGiorgis Georgakoudis 
12499d38f98dSJohannes Doerfert   /// Try to delete parallel regions if possible.
1250e565db49SJohannes Doerfert   bool deleteParallelRegions() {
1251e565db49SJohannes Doerfert     const unsigned CallbackCalleeOperand = 2;
1252e565db49SJohannes Doerfert 
12537cfd267cSsstefan1     OMPInformationCache::RuntimeFunctionInfo &RFI =
12547cfd267cSsstefan1         OMPInfoCache.RFIs[OMPRTL___kmpc_fork_call];
12557cfd267cSsstefan1 
1256e565db49SJohannes Doerfert     if (!RFI.Declaration)
1257e565db49SJohannes Doerfert       return false;
1258e565db49SJohannes Doerfert 
1259e565db49SJohannes Doerfert     bool Changed = false;
1260e565db49SJohannes Doerfert     auto DeleteCallCB = [&](Use &U, Function &) {
1261e565db49SJohannes Doerfert       CallInst *CI = getCallIfRegularCall(U);
1262e565db49SJohannes Doerfert       if (!CI)
1263e565db49SJohannes Doerfert         return false;
1264e565db49SJohannes Doerfert       auto *Fn = dyn_cast<Function>(
1265e565db49SJohannes Doerfert           CI->getArgOperand(CallbackCalleeOperand)->stripPointerCasts());
1266e565db49SJohannes Doerfert       if (!Fn)
1267e565db49SJohannes Doerfert         return false;
1268e565db49SJohannes Doerfert       if (!Fn->onlyReadsMemory())
1269e565db49SJohannes Doerfert         return false;
1270e565db49SJohannes Doerfert       if (!Fn->hasFnAttribute(Attribute::WillReturn))
1271e565db49SJohannes Doerfert         return false;
1272e565db49SJohannes Doerfert 
1273e565db49SJohannes Doerfert       LLVM_DEBUG(dbgs() << TAG << "Delete read-only parallel region in "
1274e565db49SJohannes Doerfert                         << CI->getCaller()->getName() << "\n");
12754d4ea9acSHuber, Joseph 
12764d4ea9acSHuber, Joseph       auto Remark = [&](OptimizationRemark OR) {
1277eef6601bSJoseph Huber         return OR << "Removing parallel region with no side-effects.";
12784d4ea9acSHuber, Joseph       };
12792c31d5ebSJoseph Huber       emitRemark<OptimizationRemark>(CI, "OMP160", Remark);
12804d4ea9acSHuber, Joseph 
1281e565db49SJohannes Doerfert       CGUpdater.removeCallSite(*CI);
1282e565db49SJohannes Doerfert       CI->eraseFromParent();
1283e565db49SJohannes Doerfert       Changed = true;
128455eb714aSRoman Lebedev       ++NumOpenMPParallelRegionsDeleted;
1285e565db49SJohannes Doerfert       return true;
1286e565db49SJohannes Doerfert     };
1287e565db49SJohannes Doerfert 
1288624d34afSJohannes Doerfert     RFI.foreachUse(SCC, DeleteCallCB);
1289e565db49SJohannes Doerfert 
1290e565db49SJohannes Doerfert     return Changed;
1291e565db49SJohannes Doerfert   }
1292e565db49SJohannes Doerfert 
1293b726c557SJohannes Doerfert   /// Try to eliminate runtime calls by reusing existing ones.
12949548b74aSJohannes Doerfert   bool deduplicateRuntimeCalls() {
12959548b74aSJohannes Doerfert     bool Changed = false;
12969548b74aSJohannes Doerfert 
1297e28936f6SJohannes Doerfert     RuntimeFunction DeduplicableRuntimeCallIDs[] = {
1298e28936f6SJohannes Doerfert         OMPRTL_omp_get_num_threads,
1299e28936f6SJohannes Doerfert         OMPRTL_omp_in_parallel,
1300e28936f6SJohannes Doerfert         OMPRTL_omp_get_cancellation,
1301e28936f6SJohannes Doerfert         OMPRTL_omp_get_thread_limit,
1302e28936f6SJohannes Doerfert         OMPRTL_omp_get_supported_active_levels,
1303e28936f6SJohannes Doerfert         OMPRTL_omp_get_level,
1304e28936f6SJohannes Doerfert         OMPRTL_omp_get_ancestor_thread_num,
1305e28936f6SJohannes Doerfert         OMPRTL_omp_get_team_size,
1306e28936f6SJohannes Doerfert         OMPRTL_omp_get_active_level,
1307e28936f6SJohannes Doerfert         OMPRTL_omp_in_final,
1308e28936f6SJohannes Doerfert         OMPRTL_omp_get_proc_bind,
1309e28936f6SJohannes Doerfert         OMPRTL_omp_get_num_places,
1310e28936f6SJohannes Doerfert         OMPRTL_omp_get_num_procs,
1311e28936f6SJohannes Doerfert         OMPRTL_omp_get_place_num,
1312e28936f6SJohannes Doerfert         OMPRTL_omp_get_partition_num_places,
1313e28936f6SJohannes Doerfert         OMPRTL_omp_get_partition_place_nums};
1314e28936f6SJohannes Doerfert 
1315bc93c2d7SMarek Kurdej     // Global-tid is handled separately.
13169548b74aSJohannes Doerfert     SmallSetVector<Value *, 16> GTIdArgs;
13179548b74aSJohannes Doerfert     collectGlobalThreadIdArguments(GTIdArgs);
13189548b74aSJohannes Doerfert     LLVM_DEBUG(dbgs() << TAG << "Found " << GTIdArgs.size()
13199548b74aSJohannes Doerfert                       << " global thread ID arguments\n");
13209548b74aSJohannes Doerfert 
13219548b74aSJohannes Doerfert     for (Function *F : SCC) {
1322e28936f6SJohannes Doerfert       for (auto DeduplicableRuntimeCallID : DeduplicableRuntimeCallIDs)
13234e29d256Sserge-sans-paille         Changed |= deduplicateRuntimeCalls(
13244e29d256Sserge-sans-paille             *F, OMPInfoCache.RFIs[DeduplicableRuntimeCallID]);
1325e28936f6SJohannes Doerfert 
1326e28936f6SJohannes Doerfert       // __kmpc_global_thread_num is special as we can replace it with an
1327e28936f6SJohannes Doerfert       // argument in enough cases to make it worth trying.
13289548b74aSJohannes Doerfert       Value *GTIdArg = nullptr;
13299548b74aSJohannes Doerfert       for (Argument &Arg : F->args())
13309548b74aSJohannes Doerfert         if (GTIdArgs.count(&Arg)) {
13319548b74aSJohannes Doerfert           GTIdArg = &Arg;
13329548b74aSJohannes Doerfert           break;
13339548b74aSJohannes Doerfert         }
13349548b74aSJohannes Doerfert       Changed |= deduplicateRuntimeCalls(
13357cfd267cSsstefan1           *F, OMPInfoCache.RFIs[OMPRTL___kmpc_global_thread_num], GTIdArg);
13369548b74aSJohannes Doerfert     }
13379548b74aSJohannes Doerfert 
13389548b74aSJohannes Doerfert     return Changed;
13399548b74aSJohannes Doerfert   }
13409548b74aSJohannes Doerfert 
1341496f8e5bSHamilton Tobon Mosquera   /// Tries to hide the latency of runtime calls that involve host to
1342496f8e5bSHamilton Tobon Mosquera   /// device memory transfers by splitting them into their "issue" and "wait"
1343496f8e5bSHamilton Tobon Mosquera   /// versions. The "issue" is moved upwards as much as possible. The "wait" is
1344496f8e5bSHamilton Tobon Mosquera   /// moved downards as much as possible. The "issue" issues the memory transfer
1345496f8e5bSHamilton Tobon Mosquera   /// asynchronously, returning a handle. The "wait" waits in the returned
1346496f8e5bSHamilton Tobon Mosquera   /// handle for the memory transfer to finish.
1347496f8e5bSHamilton Tobon Mosquera   bool hideMemTransfersLatency() {
1348496f8e5bSHamilton Tobon Mosquera     auto &RFI = OMPInfoCache.RFIs[OMPRTL___tgt_target_data_begin_mapper];
1349496f8e5bSHamilton Tobon Mosquera     bool Changed = false;
1350496f8e5bSHamilton Tobon Mosquera     auto SplitMemTransfers = [&](Use &U, Function &Decl) {
1351496f8e5bSHamilton Tobon Mosquera       auto *RTCall = getCallIfRegularCall(U, &RFI);
1352496f8e5bSHamilton Tobon Mosquera       if (!RTCall)
1353496f8e5bSHamilton Tobon Mosquera         return false;
1354496f8e5bSHamilton Tobon Mosquera 
13558931add6SHamilton Tobon Mosquera       OffloadArray OffloadArrays[3];
13568931add6SHamilton Tobon Mosquera       if (!getValuesInOffloadArrays(*RTCall, OffloadArrays))
13578931add6SHamilton Tobon Mosquera         return false;
13588931add6SHamilton Tobon Mosquera 
13598931add6SHamilton Tobon Mosquera       LLVM_DEBUG(dumpValuesInOffloadArrays(OffloadArrays));
13608931add6SHamilton Tobon Mosquera 
1361bd2fa181SHamilton Tobon Mosquera       // TODO: Check if can be moved upwards.
1362bd2fa181SHamilton Tobon Mosquera       bool WasSplit = false;
1363bd2fa181SHamilton Tobon Mosquera       Instruction *WaitMovementPoint = canBeMovedDownwards(*RTCall);
1364bd2fa181SHamilton Tobon Mosquera       if (WaitMovementPoint)
1365bd2fa181SHamilton Tobon Mosquera         WasSplit = splitTargetDataBeginRTC(*RTCall, *WaitMovementPoint);
1366bd2fa181SHamilton Tobon Mosquera 
1367496f8e5bSHamilton Tobon Mosquera       Changed |= WasSplit;
1368496f8e5bSHamilton Tobon Mosquera       return WasSplit;
1369496f8e5bSHamilton Tobon Mosquera     };
1370496f8e5bSHamilton Tobon Mosquera     RFI.foreachUse(SCC, SplitMemTransfers);
1371496f8e5bSHamilton Tobon Mosquera 
1372496f8e5bSHamilton Tobon Mosquera     return Changed;
1373496f8e5bSHamilton Tobon Mosquera   }
1374496f8e5bSHamilton Tobon Mosquera 
1375a2281419SJoseph Huber   void analysisGlobalization() {
13766fc51c9fSJoseph Huber     auto &RFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
137782453e75SJoseph Huber 
137882453e75SJoseph Huber     auto CheckGlobalization = [&](Use &U, Function &Decl) {
1379a2281419SJoseph Huber       if (CallInst *CI = getCallIfRegularCall(U, &RFI)) {
138044feacc7SJoseph Huber         auto Remark = [&](OptimizationRemarkMissed ORM) {
138144feacc7SJoseph Huber           return ORM
1382a2281419SJoseph Huber                  << "Found thread data sharing on the GPU. "
1383a2281419SJoseph Huber                  << "Expect degraded performance due to data globalization.";
1384a2281419SJoseph Huber         };
13852c31d5ebSJoseph Huber         emitRemark<OptimizationRemarkMissed>(CI, "OMP112", Remark);
1386a2281419SJoseph Huber       }
1387a2281419SJoseph Huber 
1388a2281419SJoseph Huber       return false;
1389a2281419SJoseph Huber     };
1390a2281419SJoseph Huber 
139182453e75SJoseph Huber     RFI.foreachUse(SCC, CheckGlobalization);
139282453e75SJoseph Huber   }
1393a2281419SJoseph Huber 
13948931add6SHamilton Tobon Mosquera   /// Maps the values stored in the offload arrays passed as arguments to
13958931add6SHamilton Tobon Mosquera   /// \p RuntimeCall into the offload arrays in \p OAs.
13968931add6SHamilton Tobon Mosquera   bool getValuesInOffloadArrays(CallInst &RuntimeCall,
13978931add6SHamilton Tobon Mosquera                                 MutableArrayRef<OffloadArray> OAs) {
13988931add6SHamilton Tobon Mosquera     assert(OAs.size() == 3 && "Need space for three offload arrays!");
13998931add6SHamilton Tobon Mosquera 
14008931add6SHamilton Tobon Mosquera     // A runtime call that involves memory offloading looks something like:
14018931add6SHamilton Tobon Mosquera     // call void @__tgt_target_data_begin_mapper(arg0, arg1,
14028931add6SHamilton Tobon Mosquera     //   i8** %offload_baseptrs, i8** %offload_ptrs, i64* %offload_sizes,
14038931add6SHamilton Tobon Mosquera     // ...)
14048931add6SHamilton Tobon Mosquera     // So, the idea is to access the allocas that allocate space for these
14058931add6SHamilton Tobon Mosquera     // offload arrays, offload_baseptrs, offload_ptrs, offload_sizes.
14068931add6SHamilton Tobon Mosquera     // Therefore:
14078931add6SHamilton Tobon Mosquera     // i8** %offload_baseptrs.
14081d3d9b9cSHamilton Tobon Mosquera     Value *BasePtrsArg =
14091d3d9b9cSHamilton Tobon Mosquera         RuntimeCall.getArgOperand(OffloadArray::BasePtrsArgNum);
14108931add6SHamilton Tobon Mosquera     // i8** %offload_ptrs.
14111d3d9b9cSHamilton Tobon Mosquera     Value *PtrsArg = RuntimeCall.getArgOperand(OffloadArray::PtrsArgNum);
14128931add6SHamilton Tobon Mosquera     // i8** %offload_sizes.
14131d3d9b9cSHamilton Tobon Mosquera     Value *SizesArg = RuntimeCall.getArgOperand(OffloadArray::SizesArgNum);
14148931add6SHamilton Tobon Mosquera 
14158931add6SHamilton Tobon Mosquera     // Get values stored in **offload_baseptrs.
14168931add6SHamilton Tobon Mosquera     auto *V = getUnderlyingObject(BasePtrsArg);
14178931add6SHamilton Tobon Mosquera     if (!isa<AllocaInst>(V))
14188931add6SHamilton Tobon Mosquera       return false;
14198931add6SHamilton Tobon Mosquera     auto *BasePtrsArray = cast<AllocaInst>(V);
14208931add6SHamilton Tobon Mosquera     if (!OAs[0].initialize(*BasePtrsArray, RuntimeCall))
14218931add6SHamilton Tobon Mosquera       return false;
14228931add6SHamilton Tobon Mosquera 
14238931add6SHamilton Tobon Mosquera     // Get values stored in **offload_baseptrs.
14248931add6SHamilton Tobon Mosquera     V = getUnderlyingObject(PtrsArg);
14258931add6SHamilton Tobon Mosquera     if (!isa<AllocaInst>(V))
14268931add6SHamilton Tobon Mosquera       return false;
14278931add6SHamilton Tobon Mosquera     auto *PtrsArray = cast<AllocaInst>(V);
14288931add6SHamilton Tobon Mosquera     if (!OAs[1].initialize(*PtrsArray, RuntimeCall))
14298931add6SHamilton Tobon Mosquera       return false;
14308931add6SHamilton Tobon Mosquera 
14318931add6SHamilton Tobon Mosquera     // Get values stored in **offload_sizes.
14328931add6SHamilton Tobon Mosquera     V = getUnderlyingObject(SizesArg);
14338931add6SHamilton Tobon Mosquera     // If it's a [constant] global array don't analyze it.
14348931add6SHamilton Tobon Mosquera     if (isa<GlobalValue>(V))
14358931add6SHamilton Tobon Mosquera       return isa<Constant>(V);
14368931add6SHamilton Tobon Mosquera     if (!isa<AllocaInst>(V))
14378931add6SHamilton Tobon Mosquera       return false;
14388931add6SHamilton Tobon Mosquera 
14398931add6SHamilton Tobon Mosquera     auto *SizesArray = cast<AllocaInst>(V);
14408931add6SHamilton Tobon Mosquera     if (!OAs[2].initialize(*SizesArray, RuntimeCall))
14418931add6SHamilton Tobon Mosquera       return false;
14428931add6SHamilton Tobon Mosquera 
14438931add6SHamilton Tobon Mosquera     return true;
14448931add6SHamilton Tobon Mosquera   }
14458931add6SHamilton Tobon Mosquera 
14468931add6SHamilton Tobon Mosquera   /// Prints the values in the OffloadArrays \p OAs using LLVM_DEBUG.
14478931add6SHamilton Tobon Mosquera   /// For now this is a way to test that the function getValuesInOffloadArrays
14488931add6SHamilton Tobon Mosquera   /// is working properly.
14498931add6SHamilton Tobon Mosquera   /// TODO: Move this to a unittest when unittests are available for OpenMPOpt.
14508931add6SHamilton Tobon Mosquera   void dumpValuesInOffloadArrays(ArrayRef<OffloadArray> OAs) {
14518931add6SHamilton Tobon Mosquera     assert(OAs.size() == 3 && "There are three offload arrays to debug!");
14528931add6SHamilton Tobon Mosquera 
14538931add6SHamilton Tobon Mosquera     LLVM_DEBUG(dbgs() << TAG << " Successfully got offload values:\n");
14548931add6SHamilton Tobon Mosquera     std::string ValuesStr;
14558931add6SHamilton Tobon Mosquera     raw_string_ostream Printer(ValuesStr);
14568931add6SHamilton Tobon Mosquera     std::string Separator = " --- ";
14578931add6SHamilton Tobon Mosquera 
14588931add6SHamilton Tobon Mosquera     for (auto *BP : OAs[0].StoredValues) {
14598931add6SHamilton Tobon Mosquera       BP->print(Printer);
14608931add6SHamilton Tobon Mosquera       Printer << Separator;
14618931add6SHamilton Tobon Mosquera     }
14628931add6SHamilton Tobon Mosquera     LLVM_DEBUG(dbgs() << "\t\toffload_baseptrs: " << Printer.str() << "\n");
14638931add6SHamilton Tobon Mosquera     ValuesStr.clear();
14648931add6SHamilton Tobon Mosquera 
14658931add6SHamilton Tobon Mosquera     for (auto *P : OAs[1].StoredValues) {
14668931add6SHamilton Tobon Mosquera       P->print(Printer);
14678931add6SHamilton Tobon Mosquera       Printer << Separator;
14688931add6SHamilton Tobon Mosquera     }
14698931add6SHamilton Tobon Mosquera     LLVM_DEBUG(dbgs() << "\t\toffload_ptrs: " << Printer.str() << "\n");
14708931add6SHamilton Tobon Mosquera     ValuesStr.clear();
14718931add6SHamilton Tobon Mosquera 
14728931add6SHamilton Tobon Mosquera     for (auto *S : OAs[2].StoredValues) {
14738931add6SHamilton Tobon Mosquera       S->print(Printer);
14748931add6SHamilton Tobon Mosquera       Printer << Separator;
14758931add6SHamilton Tobon Mosquera     }
14768931add6SHamilton Tobon Mosquera     LLVM_DEBUG(dbgs() << "\t\toffload_sizes: " << Printer.str() << "\n");
14778931add6SHamilton Tobon Mosquera   }
14788931add6SHamilton Tobon Mosquera 
1479bd2fa181SHamilton Tobon Mosquera   /// Returns the instruction where the "wait" counterpart \p RuntimeCall can be
1480bd2fa181SHamilton Tobon Mosquera   /// moved. Returns nullptr if the movement is not possible, or not worth it.
1481bd2fa181SHamilton Tobon Mosquera   Instruction *canBeMovedDownwards(CallInst &RuntimeCall) {
1482bd2fa181SHamilton Tobon Mosquera     // FIXME: This traverses only the BasicBlock where RuntimeCall is.
1483bd2fa181SHamilton Tobon Mosquera     //  Make it traverse the CFG.
1484bd2fa181SHamilton Tobon Mosquera 
1485bd2fa181SHamilton Tobon Mosquera     Instruction *CurrentI = &RuntimeCall;
1486bd2fa181SHamilton Tobon Mosquera     bool IsWorthIt = false;
1487bd2fa181SHamilton Tobon Mosquera     while ((CurrentI = CurrentI->getNextNode())) {
1488bd2fa181SHamilton Tobon Mosquera 
1489bd2fa181SHamilton Tobon Mosquera       // TODO: Once we detect the regions to be offloaded we should use the
1490bd2fa181SHamilton Tobon Mosquera       //  alias analysis manager to check if CurrentI may modify one of
1491bd2fa181SHamilton Tobon Mosquera       //  the offloaded regions.
1492bd2fa181SHamilton Tobon Mosquera       if (CurrentI->mayHaveSideEffects() || CurrentI->mayReadFromMemory()) {
1493bd2fa181SHamilton Tobon Mosquera         if (IsWorthIt)
1494bd2fa181SHamilton Tobon Mosquera           return CurrentI;
1495bd2fa181SHamilton Tobon Mosquera 
1496bd2fa181SHamilton Tobon Mosquera         return nullptr;
1497bd2fa181SHamilton Tobon Mosquera       }
1498bd2fa181SHamilton Tobon Mosquera 
1499bd2fa181SHamilton Tobon Mosquera       // FIXME: For now if we move it over anything without side effect
1500bd2fa181SHamilton Tobon Mosquera       //  is worth it.
1501bd2fa181SHamilton Tobon Mosquera       IsWorthIt = true;
1502bd2fa181SHamilton Tobon Mosquera     }
1503bd2fa181SHamilton Tobon Mosquera 
1504bd2fa181SHamilton Tobon Mosquera     // Return end of BasicBlock.
1505bd2fa181SHamilton Tobon Mosquera     return RuntimeCall.getParent()->getTerminator();
1506bd2fa181SHamilton Tobon Mosquera   }
1507bd2fa181SHamilton Tobon Mosquera 
1508496f8e5bSHamilton Tobon Mosquera   /// Splits \p RuntimeCall into its "issue" and "wait" counterparts.
1509bd2fa181SHamilton Tobon Mosquera   bool splitTargetDataBeginRTC(CallInst &RuntimeCall,
1510bd2fa181SHamilton Tobon Mosquera                                Instruction &WaitMovementPoint) {
1511bd31abc1SHamilton Tobon Mosquera     // Create stack allocated handle (__tgt_async_info) at the beginning of the
1512bd31abc1SHamilton Tobon Mosquera     // function. Used for storing information of the async transfer, allowing to
1513bd31abc1SHamilton Tobon Mosquera     // wait on it later.
1514496f8e5bSHamilton Tobon Mosquera     auto &IRBuilder = OMPInfoCache.OMPBuilder;
1515bd31abc1SHamilton Tobon Mosquera     auto *F = RuntimeCall.getCaller();
1516bd31abc1SHamilton Tobon Mosquera     Instruction *FirstInst = &(F->getEntryBlock().front());
1517bd31abc1SHamilton Tobon Mosquera     AllocaInst *Handle = new AllocaInst(
1518bd31abc1SHamilton Tobon Mosquera         IRBuilder.AsyncInfo, F->getAddressSpace(), "handle", FirstInst);
1519bd31abc1SHamilton Tobon Mosquera 
1520496f8e5bSHamilton Tobon Mosquera     // Add "issue" runtime call declaration:
1521496f8e5bSHamilton Tobon Mosquera     // declare %struct.tgt_async_info @__tgt_target_data_begin_issue(i64, i32,
1522496f8e5bSHamilton Tobon Mosquera     //   i8**, i8**, i64*, i64*)
1523496f8e5bSHamilton Tobon Mosquera     FunctionCallee IssueDecl = IRBuilder.getOrCreateRuntimeFunction(
1524496f8e5bSHamilton Tobon Mosquera         M, OMPRTL___tgt_target_data_begin_mapper_issue);
1525496f8e5bSHamilton Tobon Mosquera 
1526496f8e5bSHamilton Tobon Mosquera     // Change RuntimeCall call site for its asynchronous version.
152797e55cfeSJoseph Huber     SmallVector<Value *, 16> Args;
1528bd2fa181SHamilton Tobon Mosquera     for (auto &Arg : RuntimeCall.args())
1529496f8e5bSHamilton Tobon Mosquera       Args.push_back(Arg.get());
1530bd31abc1SHamilton Tobon Mosquera     Args.push_back(Handle);
1531496f8e5bSHamilton Tobon Mosquera 
1532496f8e5bSHamilton Tobon Mosquera     CallInst *IssueCallsite =
1533bd31abc1SHamilton Tobon Mosquera         CallInst::Create(IssueDecl, Args, /*NameStr=*/"", &RuntimeCall);
1534bd2fa181SHamilton Tobon Mosquera     RuntimeCall.eraseFromParent();
1535496f8e5bSHamilton Tobon Mosquera 
1536496f8e5bSHamilton Tobon Mosquera     // Add "wait" runtime call declaration:
1537496f8e5bSHamilton Tobon Mosquera     // declare void @__tgt_target_data_begin_wait(i64, %struct.__tgt_async_info)
1538496f8e5bSHamilton Tobon Mosquera     FunctionCallee WaitDecl = IRBuilder.getOrCreateRuntimeFunction(
1539496f8e5bSHamilton Tobon Mosquera         M, OMPRTL___tgt_target_data_begin_mapper_wait);
1540496f8e5bSHamilton Tobon Mosquera 
1541496f8e5bSHamilton Tobon Mosquera     Value *WaitParams[2] = {
1542da8bec47SJoseph Huber         IssueCallsite->getArgOperand(
1543da8bec47SJoseph Huber             OffloadArray::DeviceIDArgNum), // device_id.
1544bd31abc1SHamilton Tobon Mosquera         Handle                             // handle to wait on.
1545496f8e5bSHamilton Tobon Mosquera     };
1546bd2fa181SHamilton Tobon Mosquera     CallInst::Create(WaitDecl, WaitParams, /*NameStr=*/"", &WaitMovementPoint);
1547496f8e5bSHamilton Tobon Mosquera 
1548496f8e5bSHamilton Tobon Mosquera     return true;
1549496f8e5bSHamilton Tobon Mosquera   }
1550496f8e5bSHamilton Tobon Mosquera 
1551dc3b5b00SJohannes Doerfert   static Value *combinedIdentStruct(Value *CurrentIdent, Value *NextIdent,
1552dc3b5b00SJohannes Doerfert                                     bool GlobalOnly, bool &SingleChoice) {
1553dc3b5b00SJohannes Doerfert     if (CurrentIdent == NextIdent)
1554dc3b5b00SJohannes Doerfert       return CurrentIdent;
1555dc3b5b00SJohannes Doerfert 
1556396b7253SJohannes Doerfert     // TODO: Figure out how to actually combine multiple debug locations. For
1557dc3b5b00SJohannes Doerfert     //       now we just keep an existing one if there is a single choice.
1558dc3b5b00SJohannes Doerfert     if (!GlobalOnly || isa<GlobalValue>(NextIdent)) {
1559dc3b5b00SJohannes Doerfert       SingleChoice = !CurrentIdent;
1560dc3b5b00SJohannes Doerfert       return NextIdent;
1561dc3b5b00SJohannes Doerfert     }
1562396b7253SJohannes Doerfert     return nullptr;
1563396b7253SJohannes Doerfert   }
1564396b7253SJohannes Doerfert 
1565396b7253SJohannes Doerfert   /// Return an `struct ident_t*` value that represents the ones used in the
1566396b7253SJohannes Doerfert   /// calls of \p RFI inside of \p F. If \p GlobalOnly is true, we will not
1567396b7253SJohannes Doerfert   /// return a local `struct ident_t*`. For now, if we cannot find a suitable
1568396b7253SJohannes Doerfert   /// return value we create one from scratch. We also do not yet combine
1569396b7253SJohannes Doerfert   /// information, e.g., the source locations, see combinedIdentStruct.
15707cfd267cSsstefan1   Value *
15717cfd267cSsstefan1   getCombinedIdentFromCallUsesIn(OMPInformationCache::RuntimeFunctionInfo &RFI,
15727cfd267cSsstefan1                                  Function &F, bool GlobalOnly) {
1573dc3b5b00SJohannes Doerfert     bool SingleChoice = true;
1574396b7253SJohannes Doerfert     Value *Ident = nullptr;
1575396b7253SJohannes Doerfert     auto CombineIdentStruct = [&](Use &U, Function &Caller) {
1576396b7253SJohannes Doerfert       CallInst *CI = getCallIfRegularCall(U, &RFI);
1577396b7253SJohannes Doerfert       if (!CI || &F != &Caller)
1578396b7253SJohannes Doerfert         return false;
1579396b7253SJohannes Doerfert       Ident = combinedIdentStruct(Ident, CI->getArgOperand(0),
1580dc3b5b00SJohannes Doerfert                                   /* GlobalOnly */ true, SingleChoice);
1581396b7253SJohannes Doerfert       return false;
1582396b7253SJohannes Doerfert     };
1583624d34afSJohannes Doerfert     RFI.foreachUse(SCC, CombineIdentStruct);
1584396b7253SJohannes Doerfert 
1585dc3b5b00SJohannes Doerfert     if (!Ident || !SingleChoice) {
1586396b7253SJohannes Doerfert       // The IRBuilder uses the insertion block to get to the module, this is
1587396b7253SJohannes Doerfert       // unfortunate but we work around it for now.
15887cfd267cSsstefan1       if (!OMPInfoCache.OMPBuilder.getInsertionPoint().getBlock())
15897cfd267cSsstefan1         OMPInfoCache.OMPBuilder.updateToLocation(OpenMPIRBuilder::InsertPointTy(
1590396b7253SJohannes Doerfert             &F.getEntryBlock(), F.getEntryBlock().begin()));
1591396b7253SJohannes Doerfert       // Create a fallback location if non was found.
1592396b7253SJohannes Doerfert       // TODO: Use the debug locations of the calls instead.
1593944aa042SJohannes Doerfert       uint32_t SrcLocStrSize;
1594944aa042SJohannes Doerfert       Constant *Loc =
1595944aa042SJohannes Doerfert           OMPInfoCache.OMPBuilder.getOrCreateDefaultSrcLocStr(SrcLocStrSize);
1596944aa042SJohannes Doerfert       Ident = OMPInfoCache.OMPBuilder.getOrCreateIdent(Loc, SrcLocStrSize);
1597396b7253SJohannes Doerfert     }
1598396b7253SJohannes Doerfert     return Ident;
1599396b7253SJohannes Doerfert   }
1600396b7253SJohannes Doerfert 
1601b726c557SJohannes Doerfert   /// Try to eliminate calls of \p RFI in \p F by reusing an existing one or
16029548b74aSJohannes Doerfert   /// \p ReplVal if given.
16037cfd267cSsstefan1   bool deduplicateRuntimeCalls(Function &F,
16047cfd267cSsstefan1                                OMPInformationCache::RuntimeFunctionInfo &RFI,
16059548b74aSJohannes Doerfert                                Value *ReplVal = nullptr) {
16068855fec3SJohannes Doerfert     auto *UV = RFI.getUseVector(F);
16078855fec3SJohannes Doerfert     if (!UV || UV->size() + (ReplVal != nullptr) < 2)
1608b1fbf438SRoman Lebedev       return false;
1609b1fbf438SRoman Lebedev 
16107cfd267cSsstefan1     LLVM_DEBUG(
16117cfd267cSsstefan1         dbgs() << TAG << "Deduplicate " << UV->size() << " uses of " << RFI.Name
16127cfd267cSsstefan1                << (ReplVal ? " with an existing value\n" : "\n") << "\n");
16137cfd267cSsstefan1 
1614ab3da5ddSMichael Liao     assert((!ReplVal || (isa<Argument>(ReplVal) &&
1615ab3da5ddSMichael Liao                          cast<Argument>(ReplVal)->getParent() == &F)) &&
16169548b74aSJohannes Doerfert            "Unexpected replacement value!");
1617396b7253SJohannes Doerfert 
1618396b7253SJohannes Doerfert     // TODO: Use dominance to find a good position instead.
16196aab27baSsstefan1     auto CanBeMoved = [this](CallBase &CB) {
16204f0225f6SKazu Hirata       unsigned NumArgs = CB.arg_size();
1621396b7253SJohannes Doerfert       if (NumArgs == 0)
1622396b7253SJohannes Doerfert         return true;
16236aab27baSsstefan1       if (CB.getArgOperand(0)->getType() != OMPInfoCache.OMPBuilder.IdentPtr)
1624396b7253SJohannes Doerfert         return false;
1625c11ebfeaSJoseph Huber       for (unsigned U = 1; U < NumArgs; ++U)
1626c11ebfeaSJoseph Huber         if (isa<Instruction>(CB.getArgOperand(U)))
1627396b7253SJohannes Doerfert           return false;
1628396b7253SJohannes Doerfert       return true;
1629396b7253SJohannes Doerfert     };
1630396b7253SJohannes Doerfert 
16319548b74aSJohannes Doerfert     if (!ReplVal) {
16328855fec3SJohannes Doerfert       for (Use *U : *UV)
16339548b74aSJohannes Doerfert         if (CallInst *CI = getCallIfRegularCall(*U, &RFI)) {
1634396b7253SJohannes Doerfert           if (!CanBeMoved(*CI))
1635396b7253SJohannes Doerfert             continue;
16364d4ea9acSHuber, Joseph 
1637f97de4cbSGiorgis Georgakoudis           // If the function is a kernel, dedup will move
1638f97de4cbSGiorgis Georgakoudis           // the runtime call right after the kernel init callsite. Otherwise,
1639f97de4cbSGiorgis Georgakoudis           // it will move it to the beginning of the caller function.
1640f97de4cbSGiorgis Georgakoudis           if (isKernel(F)) {
1641f97de4cbSGiorgis Georgakoudis             auto &KernelInitRFI = OMPInfoCache.RFIs[OMPRTL___kmpc_target_init];
1642f97de4cbSGiorgis Georgakoudis             auto *KernelInitUV = KernelInitRFI.getUseVector(F);
1643f97de4cbSGiorgis Georgakoudis 
1644f97de4cbSGiorgis Georgakoudis             if (KernelInitUV->empty())
1645f97de4cbSGiorgis Georgakoudis               continue;
1646f97de4cbSGiorgis Georgakoudis 
1647f97de4cbSGiorgis Georgakoudis             assert(KernelInitUV->size() == 1 &&
1648f97de4cbSGiorgis Georgakoudis                    "Expected a single __kmpc_target_init in kernel\n");
1649f97de4cbSGiorgis Georgakoudis 
1650f97de4cbSGiorgis Georgakoudis             CallInst *KernelInitCI =
1651f97de4cbSGiorgis Georgakoudis                 getCallIfRegularCall(*KernelInitUV->front(), &KernelInitRFI);
1652f97de4cbSGiorgis Georgakoudis             assert(KernelInitCI &&
1653f97de4cbSGiorgis Georgakoudis                    "Expected a call to __kmpc_target_init in kernel\n");
1654f97de4cbSGiorgis Georgakoudis 
1655f97de4cbSGiorgis Georgakoudis             CI->moveAfter(KernelInitCI);
1656f97de4cbSGiorgis Georgakoudis           } else
16579548b74aSJohannes Doerfert             CI->moveBefore(&*F.getEntryBlock().getFirstInsertionPt());
16589548b74aSJohannes Doerfert           ReplVal = CI;
16599548b74aSJohannes Doerfert           break;
16609548b74aSJohannes Doerfert         }
16619548b74aSJohannes Doerfert       if (!ReplVal)
16629548b74aSJohannes Doerfert         return false;
16639548b74aSJohannes Doerfert     }
16649548b74aSJohannes Doerfert 
1665396b7253SJohannes Doerfert     // If we use a call as a replacement value we need to make sure the ident is
1666396b7253SJohannes Doerfert     // valid at the new location. For now we just pick a global one, either
1667396b7253SJohannes Doerfert     // existing and used by one of the calls, or created from scratch.
1668396b7253SJohannes Doerfert     if (CallBase *CI = dyn_cast<CallBase>(ReplVal)) {
166992c9ff6dSKazu Hirata       if (!CI->arg_empty() &&
16706aab27baSsstefan1           CI->getArgOperand(0)->getType() == OMPInfoCache.OMPBuilder.IdentPtr) {
1671396b7253SJohannes Doerfert         Value *Ident = getCombinedIdentFromCallUsesIn(RFI, F,
1672396b7253SJohannes Doerfert                                                       /* GlobalOnly */ true);
1673396b7253SJohannes Doerfert         CI->setArgOperand(0, Ident);
1674396b7253SJohannes Doerfert       }
1675396b7253SJohannes Doerfert     }
1676396b7253SJohannes Doerfert 
16779548b74aSJohannes Doerfert     bool Changed = false;
16789548b74aSJohannes Doerfert     auto ReplaceAndDeleteCB = [&](Use &U, Function &Caller) {
16799548b74aSJohannes Doerfert       CallInst *CI = getCallIfRegularCall(U, &RFI);
16809548b74aSJohannes Doerfert       if (!CI || CI == ReplVal || &F != &Caller)
16819548b74aSJohannes Doerfert         return false;
16829548b74aSJohannes Doerfert       assert(CI->getCaller() == &F && "Unexpected call!");
16834d4ea9acSHuber, Joseph 
16844d4ea9acSHuber, Joseph       auto Remark = [&](OptimizationRemark OR) {
16854d4ea9acSHuber, Joseph         return OR << "OpenMP runtime call "
1686eef6601bSJoseph Huber                   << ore::NV("OpenMPOptRuntime", RFI.Name) << " deduplicated.";
16874d4ea9acSHuber, Joseph       };
1688eef6601bSJoseph Huber       if (CI->getDebugLoc())
16892c31d5ebSJoseph Huber         emitRemark<OptimizationRemark>(CI, "OMP170", Remark);
1690eef6601bSJoseph Huber       else
16912c31d5ebSJoseph Huber         emitRemark<OptimizationRemark>(&F, "OMP170", Remark);
16924d4ea9acSHuber, Joseph 
16939548b74aSJohannes Doerfert       CGUpdater.removeCallSite(*CI);
16949548b74aSJohannes Doerfert       CI->replaceAllUsesWith(ReplVal);
16959548b74aSJohannes Doerfert       CI->eraseFromParent();
16969548b74aSJohannes Doerfert       ++NumOpenMPRuntimeCallsDeduplicated;
16979548b74aSJohannes Doerfert       Changed = true;
16989548b74aSJohannes Doerfert       return true;
16999548b74aSJohannes Doerfert     };
1700624d34afSJohannes Doerfert     RFI.foreachUse(SCC, ReplaceAndDeleteCB);
17019548b74aSJohannes Doerfert 
17029548b74aSJohannes Doerfert     return Changed;
17039548b74aSJohannes Doerfert   }
17049548b74aSJohannes Doerfert 
17059548b74aSJohannes Doerfert   /// Collect arguments that represent the global thread id in \p GTIdArgs.
17069548b74aSJohannes Doerfert   void collectGlobalThreadIdArguments(SmallSetVector<Value *, 16> &GTIdArgs) {
17079548b74aSJohannes Doerfert     // TODO: Below we basically perform a fixpoint iteration with a pessimistic
17089548b74aSJohannes Doerfert     //       initialization. We could define an AbstractAttribute instead and
17099548b74aSJohannes Doerfert     //       run the Attributor here once it can be run as an SCC pass.
17109548b74aSJohannes Doerfert 
17119548b74aSJohannes Doerfert     // Helper to check the argument \p ArgNo at all call sites of \p F for
17129548b74aSJohannes Doerfert     // a GTId.
17139548b74aSJohannes Doerfert     auto CallArgOpIsGTId = [&](Function &F, unsigned ArgNo, CallInst &RefCI) {
17149548b74aSJohannes Doerfert       if (!F.hasLocalLinkage())
17159548b74aSJohannes Doerfert         return false;
17169548b74aSJohannes Doerfert       for (Use &U : F.uses()) {
17179548b74aSJohannes Doerfert         if (CallInst *CI = getCallIfRegularCall(U)) {
17189548b74aSJohannes Doerfert           Value *ArgOp = CI->getArgOperand(ArgNo);
17199548b74aSJohannes Doerfert           if (CI == &RefCI || GTIdArgs.count(ArgOp) ||
17207cfd267cSsstefan1               getCallIfRegularCall(
17217cfd267cSsstefan1                   *ArgOp, &OMPInfoCache.RFIs[OMPRTL___kmpc_global_thread_num]))
17229548b74aSJohannes Doerfert             continue;
17239548b74aSJohannes Doerfert         }
17249548b74aSJohannes Doerfert         return false;
17259548b74aSJohannes Doerfert       }
17269548b74aSJohannes Doerfert       return true;
17279548b74aSJohannes Doerfert     };
17289548b74aSJohannes Doerfert 
17299548b74aSJohannes Doerfert     // Helper to identify uses of a GTId as GTId arguments.
17309548b74aSJohannes Doerfert     auto AddUserArgs = [&](Value &GTId) {
17319548b74aSJohannes Doerfert       for (Use &U : GTId.uses())
17329548b74aSJohannes Doerfert         if (CallInst *CI = dyn_cast<CallInst>(U.getUser()))
17339548b74aSJohannes Doerfert           if (CI->isArgOperand(&U))
17349548b74aSJohannes Doerfert             if (Function *Callee = CI->getCalledFunction())
17359548b74aSJohannes Doerfert               if (CallArgOpIsGTId(*Callee, U.getOperandNo(), *CI))
17369548b74aSJohannes Doerfert                 GTIdArgs.insert(Callee->getArg(U.getOperandNo()));
17379548b74aSJohannes Doerfert     };
17389548b74aSJohannes Doerfert 
17399548b74aSJohannes Doerfert     // The argument users of __kmpc_global_thread_num calls are GTIds.
17407cfd267cSsstefan1     OMPInformationCache::RuntimeFunctionInfo &GlobThreadNumRFI =
17417cfd267cSsstefan1         OMPInfoCache.RFIs[OMPRTL___kmpc_global_thread_num];
17427cfd267cSsstefan1 
1743624d34afSJohannes Doerfert     GlobThreadNumRFI.foreachUse(SCC, [&](Use &U, Function &F) {
17448855fec3SJohannes Doerfert       if (CallInst *CI = getCallIfRegularCall(U, &GlobThreadNumRFI))
17459548b74aSJohannes Doerfert         AddUserArgs(*CI);
17468855fec3SJohannes Doerfert       return false;
17478855fec3SJohannes Doerfert     });
17489548b74aSJohannes Doerfert 
17499548b74aSJohannes Doerfert     // Transitively search for more arguments by looking at the users of the
17509548b74aSJohannes Doerfert     // ones we know already. During the search the GTIdArgs vector is extended
17519548b74aSJohannes Doerfert     // so we cannot cache the size nor can we use a range based for.
1752c11ebfeaSJoseph Huber     for (unsigned U = 0; U < GTIdArgs.size(); ++U)
1753c11ebfeaSJoseph Huber       AddUserArgs(*GTIdArgs[U]);
17549548b74aSJohannes Doerfert   }
17559548b74aSJohannes Doerfert 
17565b0581aeSJohannes Doerfert   /// Kernel (=GPU) optimizations and utility functions
17575b0581aeSJohannes Doerfert   ///
17585b0581aeSJohannes Doerfert   ///{{
17595b0581aeSJohannes Doerfert 
17605b0581aeSJohannes Doerfert   /// Check if \p F is a kernel, hence entry point for target offloading.
17615b0581aeSJohannes Doerfert   bool isKernel(Function &F) { return OMPInfoCache.Kernels.count(&F); }
17625b0581aeSJohannes Doerfert 
17635b0581aeSJohannes Doerfert   /// Cache to remember the unique kernel for a function.
17645b0581aeSJohannes Doerfert   DenseMap<Function *, Optional<Kernel>> UniqueKernelMap;
17655b0581aeSJohannes Doerfert 
17665b0581aeSJohannes Doerfert   /// Find the unique kernel that will execute \p F, if any.
17675b0581aeSJohannes Doerfert   Kernel getUniqueKernelFor(Function &F);
17685b0581aeSJohannes Doerfert 
17695b0581aeSJohannes Doerfert   /// Find the unique kernel that will execute \p I, if any.
17705b0581aeSJohannes Doerfert   Kernel getUniqueKernelFor(Instruction &I) {
17715b0581aeSJohannes Doerfert     return getUniqueKernelFor(*I.getFunction());
17725b0581aeSJohannes Doerfert   }
17735b0581aeSJohannes Doerfert 
17745b0581aeSJohannes Doerfert   /// Rewrite the device (=GPU) code state machine create in non-SPMD mode in
17755b0581aeSJohannes Doerfert   /// the cases we can avoid taking the address of a function.
17765b0581aeSJohannes Doerfert   bool rewriteDeviceCodeStateMachine();
17775b0581aeSJohannes Doerfert 
17785b0581aeSJohannes Doerfert   ///
17795b0581aeSJohannes Doerfert   ///}}
17805b0581aeSJohannes Doerfert 
17814d4ea9acSHuber, Joseph   /// Emit a remark generically
17824d4ea9acSHuber, Joseph   ///
17834d4ea9acSHuber, Joseph   /// This template function can be used to generically emit a remark. The
17844d4ea9acSHuber, Joseph   /// RemarkKind should be one of the following:
17854d4ea9acSHuber, Joseph   ///   - OptimizationRemark to indicate a successful optimization attempt
17864d4ea9acSHuber, Joseph   ///   - OptimizationRemarkMissed to report a failed optimization attempt
17874d4ea9acSHuber, Joseph   ///   - OptimizationRemarkAnalysis to provide additional information about an
17884d4ea9acSHuber, Joseph   ///     optimization attempt
17894d4ea9acSHuber, Joseph   ///
17904d4ea9acSHuber, Joseph   /// The remark is built using a callback function provided by the caller that
17914d4ea9acSHuber, Joseph   /// takes a RemarkKind as input and returns a RemarkKind.
17922db182ffSJoseph Huber   template <typename RemarkKind, typename RemarkCallBack>
17932db182ffSJoseph Huber   void emitRemark(Instruction *I, StringRef RemarkName,
1794e8039ad4SJohannes Doerfert                   RemarkCallBack &&RemarkCB) const {
17952db182ffSJoseph Huber     Function *F = I->getParent()->getParent();
17964d4ea9acSHuber, Joseph     auto &ORE = OREGetter(F);
17974d4ea9acSHuber, Joseph 
17982c31d5ebSJoseph Huber     if (RemarkName.startswith("OMP"))
17992c31d5ebSJoseph Huber       ORE.emit([&]() {
18002c31d5ebSJoseph Huber         return RemarkCB(RemarkKind(DEBUG_TYPE, RemarkName, I))
18012c31d5ebSJoseph Huber                << " [" << RemarkName << "]";
18022c31d5ebSJoseph Huber       });
18032c31d5ebSJoseph Huber     else
18042c31d5ebSJoseph Huber       ORE.emit(
18052c31d5ebSJoseph Huber           [&]() { return RemarkCB(RemarkKind(DEBUG_TYPE, RemarkName, I)); });
18064d4ea9acSHuber, Joseph   }
18074d4ea9acSHuber, Joseph 
18082db182ffSJoseph Huber   /// Emit a remark on a function.
18092db182ffSJoseph Huber   template <typename RemarkKind, typename RemarkCallBack>
18102db182ffSJoseph Huber   void emitRemark(Function *F, StringRef RemarkName,
18112db182ffSJoseph Huber                   RemarkCallBack &&RemarkCB) const {
18120f426935Ssstefan1     auto &ORE = OREGetter(F);
18130f426935Ssstefan1 
18142c31d5ebSJoseph Huber     if (RemarkName.startswith("OMP"))
18152c31d5ebSJoseph Huber       ORE.emit([&]() {
18162c31d5ebSJoseph Huber         return RemarkCB(RemarkKind(DEBUG_TYPE, RemarkName, F))
18172c31d5ebSJoseph Huber                << " [" << RemarkName << "]";
18182c31d5ebSJoseph Huber       });
18192c31d5ebSJoseph Huber     else
18202c31d5ebSJoseph Huber       ORE.emit(
18212c31d5ebSJoseph Huber           [&]() { return RemarkCB(RemarkKind(DEBUG_TYPE, RemarkName, F)); });
18220f426935Ssstefan1   }
18230f426935Ssstefan1 
182458725c12SJoseph Huber   /// RAII struct to temporarily change an RTL function's linkage to external.
182558725c12SJoseph Huber   /// This prevents it from being mistakenly removed by other optimizations.
182658725c12SJoseph Huber   struct ExternalizationRAII {
182758725c12SJoseph Huber     ExternalizationRAII(OMPInformationCache &OMPInfoCache,
182858725c12SJoseph Huber                         RuntimeFunction RFKind)
1829e757a3b0SJoseph Huber         : Declaration(OMPInfoCache.RFIs[RFKind].Declaration) {
183058725c12SJoseph Huber       if (!Declaration)
183158725c12SJoseph Huber         return;
183258725c12SJoseph Huber 
183358725c12SJoseph Huber       LinkageType = Declaration->getLinkage();
183458725c12SJoseph Huber       Declaration->setLinkage(GlobalValue::ExternalLinkage);
183558725c12SJoseph Huber     }
183658725c12SJoseph Huber 
183758725c12SJoseph Huber     ~ExternalizationRAII() {
183858725c12SJoseph Huber       if (!Declaration)
183958725c12SJoseph Huber         return;
184058725c12SJoseph Huber 
184158725c12SJoseph Huber       Declaration->setLinkage(LinkageType);
184258725c12SJoseph Huber     }
184358725c12SJoseph Huber 
184458725c12SJoseph Huber     Function *Declaration;
184558725c12SJoseph Huber     GlobalValue::LinkageTypes LinkageType;
184658725c12SJoseph Huber   };
184758725c12SJoseph Huber 
1848b726c557SJohannes Doerfert   /// The underlying module.
18499548b74aSJohannes Doerfert   Module &M;
18509548b74aSJohannes Doerfert 
18519548b74aSJohannes Doerfert   /// The SCC we are operating on.
1852ee17263aSJohannes Doerfert   SmallVectorImpl<Function *> &SCC;
18539548b74aSJohannes Doerfert 
18549548b74aSJohannes Doerfert   /// Callback to update the call graph, the first argument is a removed call,
18559548b74aSJohannes Doerfert   /// the second an optional replacement call.
18569548b74aSJohannes Doerfert   CallGraphUpdater &CGUpdater;
18579548b74aSJohannes Doerfert 
18584d4ea9acSHuber, Joseph   /// Callback to get an OptimizationRemarkEmitter from a Function *
18594d4ea9acSHuber, Joseph   OptimizationRemarkGetter OREGetter;
18604d4ea9acSHuber, Joseph 
18617cfd267cSsstefan1   /// OpenMP-specific information cache. Also Used for Attributor runs.
18627cfd267cSsstefan1   OMPInformationCache &OMPInfoCache;
1863b8235d2bSsstefan1 
1864b8235d2bSsstefan1   /// Attributor instance.
1865b8235d2bSsstefan1   Attributor &A;
1866b8235d2bSsstefan1 
1867b8235d2bSsstefan1   /// Helper function to run Attributor on SCC.
1868d9659bf6SJohannes Doerfert   bool runAttributor(bool IsModulePass) {
1869b8235d2bSsstefan1     if (SCC.empty())
1870b8235d2bSsstefan1       return false;
1871b8235d2bSsstefan1 
187258725c12SJoseph Huber     // Temporarily make these function have external linkage so the Attributor
187358725c12SJoseph Huber     // doesn't remove them when we try to look them up later.
187458725c12SJoseph Huber     ExternalizationRAII Parallel(OMPInfoCache, OMPRTL___kmpc_kernel_parallel);
187558725c12SJoseph Huber     ExternalizationRAII EndParallel(OMPInfoCache,
187658725c12SJoseph Huber                                     OMPRTL___kmpc_kernel_end_parallel);
187758725c12SJoseph Huber     ExternalizationRAII BarrierSPMD(OMPInfoCache,
187858725c12SJoseph Huber                                     OMPRTL___kmpc_barrier_simple_spmd);
187973720c80SJohannes Doerfert     ExternalizationRAII BarrierGeneric(OMPInfoCache,
188073720c80SJohannes Doerfert                                        OMPRTL___kmpc_barrier_simple_generic);
18811cf86df8SJoseph Huber     ExternalizationRAII ThreadId(OMPInfoCache,
18821cf86df8SJoseph Huber                                  OMPRTL___kmpc_get_hardware_thread_id_in_block);
18837986a5f2SJoseph Huber     ExternalizationRAII WarpSize(OMPInfoCache, OMPRTL___kmpc_get_warp_size);
188458725c12SJoseph Huber 
1885d9659bf6SJohannes Doerfert     registerAAs(IsModulePass);
1886b8235d2bSsstefan1 
1887b8235d2bSsstefan1     ChangeStatus Changed = A.run();
1888b8235d2bSsstefan1 
1889b8235d2bSsstefan1     LLVM_DEBUG(dbgs() << "[Attributor] Done with " << SCC.size()
1890b8235d2bSsstefan1                       << " functions, result: " << Changed << ".\n");
1891b8235d2bSsstefan1 
1892b8235d2bSsstefan1     return Changed == ChangeStatus::CHANGED;
1893b8235d2bSsstefan1   }
1894b8235d2bSsstefan1 
18955ab6aeddSJose M Monsalve Diaz   void registerFoldRuntimeCall(RuntimeFunction RF);
18965ab6aeddSJose M Monsalve Diaz 
1897b8235d2bSsstefan1   /// Populate the Attributor with abstract attribute opportunities in the
1898b8235d2bSsstefan1   /// function.
1899d9659bf6SJohannes Doerfert   void registerAAs(bool IsModulePass);
1900b8235d2bSsstefan1 };
1901b8235d2bSsstefan1 
19025b0581aeSJohannes Doerfert Kernel OpenMPOpt::getUniqueKernelFor(Function &F) {
19035b0581aeSJohannes Doerfert   if (!OMPInfoCache.ModuleSlice.count(&F))
19045b0581aeSJohannes Doerfert     return nullptr;
19055b0581aeSJohannes Doerfert 
19065b0581aeSJohannes Doerfert   // Use a scope to keep the lifetime of the CachedKernel short.
19075b0581aeSJohannes Doerfert   {
19085b0581aeSJohannes Doerfert     Optional<Kernel> &CachedKernel = UniqueKernelMap[&F];
19095b0581aeSJohannes Doerfert     if (CachedKernel)
19105b0581aeSJohannes Doerfert       return *CachedKernel;
19115b0581aeSJohannes Doerfert 
19125b0581aeSJohannes Doerfert     // TODO: We should use an AA to create an (optimistic and callback
19135b0581aeSJohannes Doerfert     //       call-aware) call graph. For now we stick to simple patterns that
19145b0581aeSJohannes Doerfert     //       are less powerful, basically the worst fixpoint.
19155b0581aeSJohannes Doerfert     if (isKernel(F)) {
19165b0581aeSJohannes Doerfert       CachedKernel = Kernel(&F);
19175b0581aeSJohannes Doerfert       return *CachedKernel;
19185b0581aeSJohannes Doerfert     }
19195b0581aeSJohannes Doerfert 
19205b0581aeSJohannes Doerfert     CachedKernel = nullptr;
1921994bb6ebSJohannes Doerfert     if (!F.hasLocalLinkage()) {
1922994bb6ebSJohannes Doerfert 
1923994bb6ebSJohannes Doerfert       // See https://openmp.llvm.org/remarks/OptimizationRemarks.html
19242db182ffSJoseph Huber       auto Remark = [&](OptimizationRemarkAnalysis ORA) {
1925eef6601bSJoseph Huber         return ORA << "Potentially unknown OpenMP target region caller.";
1926994bb6ebSJohannes Doerfert       };
19272db182ffSJoseph Huber       emitRemark<OptimizationRemarkAnalysis>(&F, "OMP100", Remark);
1928994bb6ebSJohannes Doerfert 
19295b0581aeSJohannes Doerfert       return nullptr;
19305b0581aeSJohannes Doerfert     }
1931994bb6ebSJohannes Doerfert   }
19325b0581aeSJohannes Doerfert 
19335b0581aeSJohannes Doerfert   auto GetUniqueKernelForUse = [&](const Use &U) -> Kernel {
19345b0581aeSJohannes Doerfert     if (auto *Cmp = dyn_cast<ICmpInst>(U.getUser())) {
19355b0581aeSJohannes Doerfert       // Allow use in equality comparisons.
19365b0581aeSJohannes Doerfert       if (Cmp->isEquality())
19375b0581aeSJohannes Doerfert         return getUniqueKernelFor(*Cmp);
19385b0581aeSJohannes Doerfert       return nullptr;
19395b0581aeSJohannes Doerfert     }
19405b0581aeSJohannes Doerfert     if (auto *CB = dyn_cast<CallBase>(U.getUser())) {
19415b0581aeSJohannes Doerfert       // Allow direct calls.
19425b0581aeSJohannes Doerfert       if (CB->isCallee(&U))
19435b0581aeSJohannes Doerfert         return getUniqueKernelFor(*CB);
1944a2dbfb6bSGiorgis Georgakoudis 
1945a2dbfb6bSGiorgis Georgakoudis       OMPInformationCache::RuntimeFunctionInfo &KernelParallelRFI =
1946a2dbfb6bSGiorgis Georgakoudis           OMPInfoCache.RFIs[OMPRTL___kmpc_parallel_51];
1947a2dbfb6bSGiorgis Georgakoudis       // Allow the use in __kmpc_parallel_51 calls.
1948a2dbfb6bSGiorgis Georgakoudis       if (OpenMPOpt::getCallIfRegularCall(*U.getUser(), &KernelParallelRFI))
19495b0581aeSJohannes Doerfert         return getUniqueKernelFor(*CB);
19505b0581aeSJohannes Doerfert       return nullptr;
19515b0581aeSJohannes Doerfert     }
19525b0581aeSJohannes Doerfert     // Disallow every other use.
19535b0581aeSJohannes Doerfert     return nullptr;
19545b0581aeSJohannes Doerfert   };
19555b0581aeSJohannes Doerfert 
19565b0581aeSJohannes Doerfert   // TODO: In the future we want to track more than just a unique kernel.
19575b0581aeSJohannes Doerfert   SmallPtrSet<Kernel, 2> PotentialKernels;
19588d8ce85bSsstefan1   OMPInformationCache::foreachUse(F, [&](const Use &U) {
19595b0581aeSJohannes Doerfert     PotentialKernels.insert(GetUniqueKernelForUse(U));
19605b0581aeSJohannes Doerfert   });
19615b0581aeSJohannes Doerfert 
19625b0581aeSJohannes Doerfert   Kernel K = nullptr;
19635b0581aeSJohannes Doerfert   if (PotentialKernels.size() == 1)
19645b0581aeSJohannes Doerfert     K = *PotentialKernels.begin();
19655b0581aeSJohannes Doerfert 
19665b0581aeSJohannes Doerfert   // Cache the result.
19675b0581aeSJohannes Doerfert   UniqueKernelMap[&F] = K;
19685b0581aeSJohannes Doerfert 
19695b0581aeSJohannes Doerfert   return K;
19705b0581aeSJohannes Doerfert }
19715b0581aeSJohannes Doerfert 
19725b0581aeSJohannes Doerfert bool OpenMPOpt::rewriteDeviceCodeStateMachine() {
1973a2dbfb6bSGiorgis Georgakoudis   OMPInformationCache::RuntimeFunctionInfo &KernelParallelRFI =
1974a2dbfb6bSGiorgis Georgakoudis       OMPInfoCache.RFIs[OMPRTL___kmpc_parallel_51];
19755b0581aeSJohannes Doerfert 
19765b0581aeSJohannes Doerfert   bool Changed = false;
1977a2dbfb6bSGiorgis Georgakoudis   if (!KernelParallelRFI)
19785b0581aeSJohannes Doerfert     return Changed;
19795b0581aeSJohannes Doerfert 
1980cd0dd8ecSJoseph Huber   // If we have disabled state machine changes, exit
1981cd0dd8ecSJoseph Huber   if (DisableOpenMPOptStateMachineRewrite)
1982cd0dd8ecSJoseph Huber     return Changed;
1983cd0dd8ecSJoseph Huber 
19845b0581aeSJohannes Doerfert   for (Function *F : SCC) {
19855b0581aeSJohannes Doerfert 
1986a2dbfb6bSGiorgis Georgakoudis     // Check if the function is a use in a __kmpc_parallel_51 call at
19875b0581aeSJohannes Doerfert     // all.
19885b0581aeSJohannes Doerfert     bool UnknownUse = false;
1989a2dbfb6bSGiorgis Georgakoudis     bool KernelParallelUse = false;
19905b0581aeSJohannes Doerfert     unsigned NumDirectCalls = 0;
19915b0581aeSJohannes Doerfert 
19925b0581aeSJohannes Doerfert     SmallVector<Use *, 2> ToBeReplacedStateMachineUses;
19938d8ce85bSsstefan1     OMPInformationCache::foreachUse(*F, [&](Use &U) {
19945b0581aeSJohannes Doerfert       if (auto *CB = dyn_cast<CallBase>(U.getUser()))
19955b0581aeSJohannes Doerfert         if (CB->isCallee(&U)) {
19965b0581aeSJohannes Doerfert           ++NumDirectCalls;
19975b0581aeSJohannes Doerfert           return;
19985b0581aeSJohannes Doerfert         }
19995b0581aeSJohannes Doerfert 
200081db6144SMichael Liao       if (isa<ICmpInst>(U.getUser())) {
20015b0581aeSJohannes Doerfert         ToBeReplacedStateMachineUses.push_back(&U);
20025b0581aeSJohannes Doerfert         return;
20035b0581aeSJohannes Doerfert       }
2004a2dbfb6bSGiorgis Georgakoudis 
2005a2dbfb6bSGiorgis Georgakoudis       // Find wrapper functions that represent parallel kernels.
2006a2dbfb6bSGiorgis Georgakoudis       CallInst *CI =
2007a2dbfb6bSGiorgis Georgakoudis           OpenMPOpt::getCallIfRegularCall(*U.getUser(), &KernelParallelRFI);
2008a2dbfb6bSGiorgis Georgakoudis       const unsigned int WrapperFunctionArgNo = 6;
2009a2dbfb6bSGiorgis Georgakoudis       if (!KernelParallelUse && CI &&
2010a2dbfb6bSGiorgis Georgakoudis           CI->getArgOperandNo(&U) == WrapperFunctionArgNo) {
2011a2dbfb6bSGiorgis Georgakoudis         KernelParallelUse = true;
20125b0581aeSJohannes Doerfert         ToBeReplacedStateMachineUses.push_back(&U);
20135b0581aeSJohannes Doerfert         return;
20145b0581aeSJohannes Doerfert       }
20155b0581aeSJohannes Doerfert       UnknownUse = true;
20165b0581aeSJohannes Doerfert     });
20175b0581aeSJohannes Doerfert 
2018a2dbfb6bSGiorgis Georgakoudis     // Do not emit a remark if we haven't seen a __kmpc_parallel_51
2019fec1f210SJohannes Doerfert     // use.
2020a2dbfb6bSGiorgis Georgakoudis     if (!KernelParallelUse)
20215b0581aeSJohannes Doerfert       continue;
20225b0581aeSJohannes Doerfert 
2023fec1f210SJohannes Doerfert     // If this ever hits, we should investigate.
2024fec1f210SJohannes Doerfert     // TODO: Checking the number of uses is not a necessary restriction and
2025fec1f210SJohannes Doerfert     // should be lifted.
2026fec1f210SJohannes Doerfert     if (UnknownUse || NumDirectCalls != 1 ||
2027d9659bf6SJohannes Doerfert         ToBeReplacedStateMachineUses.size() > 2) {
20282db182ffSJoseph Huber       auto Remark = [&](OptimizationRemarkAnalysis ORA) {
20292db182ffSJoseph Huber         return ORA << "Parallel region is used in "
2030fec1f210SJohannes Doerfert                    << (UnknownUse ? "unknown" : "unexpected")
2031eef6601bSJoseph Huber                    << " ways. Will not attempt to rewrite the state machine.";
2032fec1f210SJohannes Doerfert       };
20332c31d5ebSJoseph Huber       emitRemark<OptimizationRemarkAnalysis>(F, "OMP101", Remark);
20345b0581aeSJohannes Doerfert       continue;
2035fec1f210SJohannes Doerfert     }
20365b0581aeSJohannes Doerfert 
2037a2dbfb6bSGiorgis Georgakoudis     // Even if we have __kmpc_parallel_51 calls, we (for now) give
20385b0581aeSJohannes Doerfert     // up if the function is not called from a unique kernel.
20395b0581aeSJohannes Doerfert     Kernel K = getUniqueKernelFor(*F);
2040fec1f210SJohannes Doerfert     if (!K) {
20412db182ffSJoseph Huber       auto Remark = [&](OptimizationRemarkAnalysis ORA) {
2042eef6601bSJoseph Huber         return ORA << "Parallel region is not called from a unique kernel. "
2043eef6601bSJoseph Huber                       "Will not attempt to rewrite the state machine.";
2044fec1f210SJohannes Doerfert       };
20452c31d5ebSJoseph Huber       emitRemark<OptimizationRemarkAnalysis>(F, "OMP102", Remark);
20465b0581aeSJohannes Doerfert       continue;
2047fec1f210SJohannes Doerfert     }
20485b0581aeSJohannes Doerfert 
20495b0581aeSJohannes Doerfert     // We now know F is a parallel body function called only from the kernel K.
20505b0581aeSJohannes Doerfert     // We also identified the state machine uses in which we replace the
20515b0581aeSJohannes Doerfert     // function pointer by a new global symbol for identification purposes. This
20525b0581aeSJohannes Doerfert     // ensures only direct calls to the function are left.
20535b0581aeSJohannes Doerfert 
20545b0581aeSJohannes Doerfert     Module &M = *F->getParent();
20555b0581aeSJohannes Doerfert     Type *Int8Ty = Type::getInt8Ty(M.getContext());
20565b0581aeSJohannes Doerfert 
20575b0581aeSJohannes Doerfert     auto *ID = new GlobalVariable(
20585b0581aeSJohannes Doerfert         M, Int8Ty, /* isConstant */ true, GlobalValue::PrivateLinkage,
20595b0581aeSJohannes Doerfert         UndefValue::get(Int8Ty), F->getName() + ".ID");
20605b0581aeSJohannes Doerfert 
20615b0581aeSJohannes Doerfert     for (Use *U : ToBeReplacedStateMachineUses)
206271052ea1SJon Chesterfield       U->set(ConstantExpr::getPointerBitCastOrAddrSpaceCast(
206371052ea1SJon Chesterfield           ID, U->get()->getType()));
20645b0581aeSJohannes Doerfert 
20655b0581aeSJohannes Doerfert     ++NumOpenMPParallelRegionsReplacedInGPUStateMachine;
20665b0581aeSJohannes Doerfert 
20675b0581aeSJohannes Doerfert     Changed = true;
20685b0581aeSJohannes Doerfert   }
20695b0581aeSJohannes Doerfert 
20705b0581aeSJohannes Doerfert   return Changed;
20715b0581aeSJohannes Doerfert }
20725b0581aeSJohannes Doerfert 
2073b8235d2bSsstefan1 /// Abstract Attribute for tracking ICV values.
2074b8235d2bSsstefan1 struct AAICVTracker : public StateWrapper<BooleanState, AbstractAttribute> {
2075b8235d2bSsstefan1   using Base = StateWrapper<BooleanState, AbstractAttribute>;
2076b8235d2bSsstefan1   AAICVTracker(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
2077b8235d2bSsstefan1 
20785dfd7cc4Ssstefan1   void initialize(Attributor &A) override {
20795dfd7cc4Ssstefan1     Function *F = getAnchorScope();
20805dfd7cc4Ssstefan1     if (!F || !A.isFunctionIPOAmendable(*F))
20815dfd7cc4Ssstefan1       indicatePessimisticFixpoint();
20825dfd7cc4Ssstefan1   }
20835dfd7cc4Ssstefan1 
2084b8235d2bSsstefan1   /// Returns true if value is assumed to be tracked.
2085b8235d2bSsstefan1   bool isAssumedTracked() const { return getAssumed(); }
2086b8235d2bSsstefan1 
2087b8235d2bSsstefan1   /// Returns true if value is known to be tracked.
2088b8235d2bSsstefan1   bool isKnownTracked() const { return getAssumed(); }
2089b8235d2bSsstefan1 
2090b8235d2bSsstefan1   /// Create an abstract attribute biew for the position \p IRP.
2091b8235d2bSsstefan1   static AAICVTracker &createForPosition(const IRPosition &IRP, Attributor &A);
2092b8235d2bSsstefan1 
2093b8235d2bSsstefan1   /// Return the value with which \p I can be replaced for specific \p ICV.
20945dfd7cc4Ssstefan1   virtual Optional<Value *> getReplacementValue(InternalControlVar ICV,
20955dfd7cc4Ssstefan1                                                 const Instruction *I,
20965dfd7cc4Ssstefan1                                                 Attributor &A) const {
20975dfd7cc4Ssstefan1     return None;
20985dfd7cc4Ssstefan1   }
20995dfd7cc4Ssstefan1 
21005dfd7cc4Ssstefan1   /// Return an assumed unique ICV value if a single candidate is found. If
21015dfd7cc4Ssstefan1   /// there cannot be one, return a nullptr. If it is not clear yet, return the
21025dfd7cc4Ssstefan1   /// Optional::NoneType.
21035dfd7cc4Ssstefan1   virtual Optional<Value *>
21045dfd7cc4Ssstefan1   getUniqueReplacementValue(InternalControlVar ICV) const = 0;
21055dfd7cc4Ssstefan1 
21065dfd7cc4Ssstefan1   // Currently only nthreads is being tracked.
21075dfd7cc4Ssstefan1   // this array will only grow with time.
21085dfd7cc4Ssstefan1   InternalControlVar TrackableICVs[1] = {ICV_nthreads};
2109b8235d2bSsstefan1 
2110b8235d2bSsstefan1   /// See AbstractAttribute::getName()
2111b8235d2bSsstefan1   const std::string getName() const override { return "AAICVTracker"; }
2112b8235d2bSsstefan1 
2113233af895SLuofan Chen   /// See AbstractAttribute::getIdAddr()
2114233af895SLuofan Chen   const char *getIdAddr() const override { return &ID; }
2115233af895SLuofan Chen 
2116233af895SLuofan Chen   /// This function should return true if the type of the \p AA is AAICVTracker
2117233af895SLuofan Chen   static bool classof(const AbstractAttribute *AA) {
2118233af895SLuofan Chen     return (AA->getIdAddr() == &ID);
2119233af895SLuofan Chen   }
2120233af895SLuofan Chen 
2121b8235d2bSsstefan1   static const char ID;
2122b8235d2bSsstefan1 };
2123b8235d2bSsstefan1 
2124b8235d2bSsstefan1 struct AAICVTrackerFunction : public AAICVTracker {
2125b8235d2bSsstefan1   AAICVTrackerFunction(const IRPosition &IRP, Attributor &A)
2126b8235d2bSsstefan1       : AAICVTracker(IRP, A) {}
2127b8235d2bSsstefan1 
2128b8235d2bSsstefan1   // FIXME: come up with better string.
21295dfd7cc4Ssstefan1   const std::string getAsStr() const override { return "ICVTrackerFunction"; }
2130b8235d2bSsstefan1 
2131b8235d2bSsstefan1   // FIXME: come up with some stats.
2132b8235d2bSsstefan1   void trackStatistics() const override {}
2133b8235d2bSsstefan1 
21345dfd7cc4Ssstefan1   /// We don't manifest anything for this AA.
2135b8235d2bSsstefan1   ChangeStatus manifest(Attributor &A) override {
21365dfd7cc4Ssstefan1     return ChangeStatus::UNCHANGED;
2137b8235d2bSsstefan1   }
2138b8235d2bSsstefan1 
2139b8235d2bSsstefan1   // Map of ICV to their values at specific program point.
21405dfd7cc4Ssstefan1   EnumeratedArray<DenseMap<Instruction *, Value *>, InternalControlVar,
2141b8235d2bSsstefan1                   InternalControlVar::ICV___last>
21425dfd7cc4Ssstefan1       ICVReplacementValuesMap;
2143b8235d2bSsstefan1 
2144b8235d2bSsstefan1   ChangeStatus updateImpl(Attributor &A) override {
2145b8235d2bSsstefan1     ChangeStatus HasChanged = ChangeStatus::UNCHANGED;
2146b8235d2bSsstefan1 
2147b8235d2bSsstefan1     Function *F = getAnchorScope();
2148b8235d2bSsstefan1 
2149b8235d2bSsstefan1     auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
2150b8235d2bSsstefan1 
2151b8235d2bSsstefan1     for (InternalControlVar ICV : TrackableICVs) {
2152b8235d2bSsstefan1       auto &SetterRFI = OMPInfoCache.RFIs[OMPInfoCache.ICVs[ICV].Setter];
2153b8235d2bSsstefan1 
21545dfd7cc4Ssstefan1       auto &ValuesMap = ICVReplacementValuesMap[ICV];
2155b8235d2bSsstefan1       auto TrackValues = [&](Use &U, Function &) {
2156b8235d2bSsstefan1         CallInst *CI = OpenMPOpt::getCallIfRegularCall(U);
2157b8235d2bSsstefan1         if (!CI)
2158b8235d2bSsstefan1           return false;
2159b8235d2bSsstefan1 
2160b8235d2bSsstefan1         // FIXME: handle setters with more that 1 arguments.
2161b8235d2bSsstefan1         /// Track new value.
21625dfd7cc4Ssstefan1         if (ValuesMap.insert(std::make_pair(CI, CI->getArgOperand(0))).second)
2163b8235d2bSsstefan1           HasChanged = ChangeStatus::CHANGED;
2164b8235d2bSsstefan1 
2165b8235d2bSsstefan1         return false;
2166b8235d2bSsstefan1       };
2167b8235d2bSsstefan1 
21685dfd7cc4Ssstefan1       auto CallCheck = [&](Instruction &I) {
21695dfd7cc4Ssstefan1         Optional<Value *> ReplVal = getValueForCall(A, &I, ICV);
21705dfd7cc4Ssstefan1         if (ReplVal.hasValue() &&
21715dfd7cc4Ssstefan1             ValuesMap.insert(std::make_pair(&I, *ReplVal)).second)
21725dfd7cc4Ssstefan1           HasChanged = ChangeStatus::CHANGED;
21735dfd7cc4Ssstefan1 
21745dfd7cc4Ssstefan1         return true;
21755dfd7cc4Ssstefan1       };
21765dfd7cc4Ssstefan1 
21775dfd7cc4Ssstefan1       // Track all changes of an ICV.
2178b8235d2bSsstefan1       SetterRFI.foreachUse(TrackValues, F);
21795dfd7cc4Ssstefan1 
2180792aac98SJohannes Doerfert       bool UsedAssumedInformation = false;
21815dfd7cc4Ssstefan1       A.checkForAllInstructions(CallCheck, *this, {Instruction::Call},
2182792aac98SJohannes Doerfert                                 UsedAssumedInformation,
21835dfd7cc4Ssstefan1                                 /* CheckBBLivenessOnly */ true);
21845dfd7cc4Ssstefan1 
21855dfd7cc4Ssstefan1       /// TODO: Figure out a way to avoid adding entry in
21865dfd7cc4Ssstefan1       /// ICVReplacementValuesMap
21875dfd7cc4Ssstefan1       Instruction *Entry = &F->getEntryBlock().front();
21885dfd7cc4Ssstefan1       if (HasChanged == ChangeStatus::CHANGED && !ValuesMap.count(Entry))
21895dfd7cc4Ssstefan1         ValuesMap.insert(std::make_pair(Entry, nullptr));
2190b8235d2bSsstefan1     }
2191b8235d2bSsstefan1 
2192b8235d2bSsstefan1     return HasChanged;
2193b8235d2bSsstefan1   }
2194b8235d2bSsstefan1 
21955dfd7cc4Ssstefan1   /// Hepler to check if \p I is a call and get the value for it if it is
21965dfd7cc4Ssstefan1   /// unique.
21975dfd7cc4Ssstefan1   Optional<Value *> getValueForCall(Attributor &A, const Instruction *I,
21985dfd7cc4Ssstefan1                                     InternalControlVar &ICV) const {
2199b8235d2bSsstefan1 
22005dfd7cc4Ssstefan1     const auto *CB = dyn_cast<CallBase>(I);
2201dcaec812SJohannes Doerfert     if (!CB || CB->hasFnAttr("no_openmp") ||
2202dcaec812SJohannes Doerfert         CB->hasFnAttr("no_openmp_routines"))
22035dfd7cc4Ssstefan1       return None;
22045dfd7cc4Ssstefan1 
2205b8235d2bSsstefan1     auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
2206b8235d2bSsstefan1     auto &GetterRFI = OMPInfoCache.RFIs[OMPInfoCache.ICVs[ICV].Getter];
22075dfd7cc4Ssstefan1     auto &SetterRFI = OMPInfoCache.RFIs[OMPInfoCache.ICVs[ICV].Setter];
22085dfd7cc4Ssstefan1     Function *CalledFunction = CB->getCalledFunction();
2209b8235d2bSsstefan1 
22104eef14f9SWei Wang     // Indirect call, assume ICV changes.
22114eef14f9SWei Wang     if (CalledFunction == nullptr)
22124eef14f9SWei Wang       return nullptr;
22135dfd7cc4Ssstefan1     if (CalledFunction == GetterRFI.Declaration)
22145dfd7cc4Ssstefan1       return None;
22155dfd7cc4Ssstefan1     if (CalledFunction == SetterRFI.Declaration) {
22165dfd7cc4Ssstefan1       if (ICVReplacementValuesMap[ICV].count(I))
22175dfd7cc4Ssstefan1         return ICVReplacementValuesMap[ICV].lookup(I);
22185dfd7cc4Ssstefan1 
22195dfd7cc4Ssstefan1       return nullptr;
22205dfd7cc4Ssstefan1     }
22215dfd7cc4Ssstefan1 
22225dfd7cc4Ssstefan1     // Since we don't know, assume it changes the ICV.
22235dfd7cc4Ssstefan1     if (CalledFunction->isDeclaration())
22245dfd7cc4Ssstefan1       return nullptr;
22255dfd7cc4Ssstefan1 
22265b70c12fSJohannes Doerfert     const auto &ICVTrackingAA = A.getAAFor<AAICVTracker>(
22275b70c12fSJohannes Doerfert         *this, IRPosition::callsite_returned(*CB), DepClassTy::REQUIRED);
22285dfd7cc4Ssstefan1 
22295dfd7cc4Ssstefan1     if (ICVTrackingAA.isAssumedTracked())
22305dfd7cc4Ssstefan1       return ICVTrackingAA.getUniqueReplacementValue(ICV);
22315dfd7cc4Ssstefan1 
22325dfd7cc4Ssstefan1     // If we don't know, assume it changes.
22335dfd7cc4Ssstefan1     return nullptr;
22345dfd7cc4Ssstefan1   }
22355dfd7cc4Ssstefan1 
22365dfd7cc4Ssstefan1   // We don't check unique value for a function, so return None.
22375dfd7cc4Ssstefan1   Optional<Value *>
22385dfd7cc4Ssstefan1   getUniqueReplacementValue(InternalControlVar ICV) const override {
22395dfd7cc4Ssstefan1     return None;
22405dfd7cc4Ssstefan1   }
22415dfd7cc4Ssstefan1 
22425dfd7cc4Ssstefan1   /// Return the value with which \p I can be replaced for specific \p ICV.
22435dfd7cc4Ssstefan1   Optional<Value *> getReplacementValue(InternalControlVar ICV,
22445dfd7cc4Ssstefan1                                         const Instruction *I,
22455dfd7cc4Ssstefan1                                         Attributor &A) const override {
22465dfd7cc4Ssstefan1     const auto &ValuesMap = ICVReplacementValuesMap[ICV];
22475dfd7cc4Ssstefan1     if (ValuesMap.count(I))
22485dfd7cc4Ssstefan1       return ValuesMap.lookup(I);
22495dfd7cc4Ssstefan1 
22505dfd7cc4Ssstefan1     SmallVector<const Instruction *, 16> Worklist;
22515dfd7cc4Ssstefan1     SmallPtrSet<const Instruction *, 16> Visited;
22525dfd7cc4Ssstefan1     Worklist.push_back(I);
22535dfd7cc4Ssstefan1 
22545dfd7cc4Ssstefan1     Optional<Value *> ReplVal;
22555dfd7cc4Ssstefan1 
22565dfd7cc4Ssstefan1     while (!Worklist.empty()) {
22575dfd7cc4Ssstefan1       const Instruction *CurrInst = Worklist.pop_back_val();
22585dfd7cc4Ssstefan1       if (!Visited.insert(CurrInst).second)
2259b8235d2bSsstefan1         continue;
2260b8235d2bSsstefan1 
22615dfd7cc4Ssstefan1       const BasicBlock *CurrBB = CurrInst->getParent();
22625dfd7cc4Ssstefan1 
22635dfd7cc4Ssstefan1       // Go up and look for all potential setters/calls that might change the
22645dfd7cc4Ssstefan1       // ICV.
22655dfd7cc4Ssstefan1       while ((CurrInst = CurrInst->getPrevNode())) {
22665dfd7cc4Ssstefan1         if (ValuesMap.count(CurrInst)) {
22675dfd7cc4Ssstefan1           Optional<Value *> NewReplVal = ValuesMap.lookup(CurrInst);
22685dfd7cc4Ssstefan1           // Unknown value, track new.
22695dfd7cc4Ssstefan1           if (!ReplVal.hasValue()) {
22705dfd7cc4Ssstefan1             ReplVal = NewReplVal;
22715dfd7cc4Ssstefan1             break;
22725dfd7cc4Ssstefan1           }
22735dfd7cc4Ssstefan1 
22745dfd7cc4Ssstefan1           // If we found a new value, we can't know the icv value anymore.
22755dfd7cc4Ssstefan1           if (NewReplVal.hasValue())
22765dfd7cc4Ssstefan1             if (ReplVal != NewReplVal)
2277b8235d2bSsstefan1               return nullptr;
2278b8235d2bSsstefan1 
22795dfd7cc4Ssstefan1           break;
2280b8235d2bSsstefan1         }
2281b8235d2bSsstefan1 
22825dfd7cc4Ssstefan1         Optional<Value *> NewReplVal = getValueForCall(A, CurrInst, ICV);
22835dfd7cc4Ssstefan1         if (!NewReplVal.hasValue())
22845dfd7cc4Ssstefan1           continue;
22855dfd7cc4Ssstefan1 
22865dfd7cc4Ssstefan1         // Unknown value, track new.
22875dfd7cc4Ssstefan1         if (!ReplVal.hasValue()) {
22885dfd7cc4Ssstefan1           ReplVal = NewReplVal;
22895dfd7cc4Ssstefan1           break;
2290b8235d2bSsstefan1         }
2291b8235d2bSsstefan1 
22925dfd7cc4Ssstefan1         // if (NewReplVal.hasValue())
22935dfd7cc4Ssstefan1         // We found a new value, we can't know the icv value anymore.
22945dfd7cc4Ssstefan1         if (ReplVal != NewReplVal)
2295b8235d2bSsstefan1           return nullptr;
2296b8235d2bSsstefan1       }
22975dfd7cc4Ssstefan1 
22985dfd7cc4Ssstefan1       // If we are in the same BB and we have a value, we are done.
22995dfd7cc4Ssstefan1       if (CurrBB == I->getParent() && ReplVal.hasValue())
23005dfd7cc4Ssstefan1         return ReplVal;
23015dfd7cc4Ssstefan1 
23025dfd7cc4Ssstefan1       // Go through all predecessors and add terminators for analysis.
23035dfd7cc4Ssstefan1       for (const BasicBlock *Pred : predecessors(CurrBB))
23045dfd7cc4Ssstefan1         if (const Instruction *Terminator = Pred->getTerminator())
23055dfd7cc4Ssstefan1           Worklist.push_back(Terminator);
23065dfd7cc4Ssstefan1     }
23075dfd7cc4Ssstefan1 
23085dfd7cc4Ssstefan1     return ReplVal;
23095dfd7cc4Ssstefan1   }
23105dfd7cc4Ssstefan1 };
23115dfd7cc4Ssstefan1 
23125dfd7cc4Ssstefan1 struct AAICVTrackerFunctionReturned : AAICVTracker {
23135dfd7cc4Ssstefan1   AAICVTrackerFunctionReturned(const IRPosition &IRP, Attributor &A)
23145dfd7cc4Ssstefan1       : AAICVTracker(IRP, A) {}
23155dfd7cc4Ssstefan1 
23165dfd7cc4Ssstefan1   // FIXME: come up with better string.
23175dfd7cc4Ssstefan1   const std::string getAsStr() const override {
23185dfd7cc4Ssstefan1     return "ICVTrackerFunctionReturned";
23195dfd7cc4Ssstefan1   }
23205dfd7cc4Ssstefan1 
23215dfd7cc4Ssstefan1   // FIXME: come up with some stats.
23225dfd7cc4Ssstefan1   void trackStatistics() const override {}
23235dfd7cc4Ssstefan1 
23245dfd7cc4Ssstefan1   /// We don't manifest anything for this AA.
23255dfd7cc4Ssstefan1   ChangeStatus manifest(Attributor &A) override {
23265dfd7cc4Ssstefan1     return ChangeStatus::UNCHANGED;
23275dfd7cc4Ssstefan1   }
23285dfd7cc4Ssstefan1 
23295dfd7cc4Ssstefan1   // Map of ICV to their values at specific program point.
23305dfd7cc4Ssstefan1   EnumeratedArray<Optional<Value *>, InternalControlVar,
23315dfd7cc4Ssstefan1                   InternalControlVar::ICV___last>
23325dfd7cc4Ssstefan1       ICVReplacementValuesMap;
23335dfd7cc4Ssstefan1 
23345dfd7cc4Ssstefan1   /// Return the value with which \p I can be replaced for specific \p ICV.
23355dfd7cc4Ssstefan1   Optional<Value *>
23365dfd7cc4Ssstefan1   getUniqueReplacementValue(InternalControlVar ICV) const override {
23375dfd7cc4Ssstefan1     return ICVReplacementValuesMap[ICV];
23385dfd7cc4Ssstefan1   }
23395dfd7cc4Ssstefan1 
23405dfd7cc4Ssstefan1   ChangeStatus updateImpl(Attributor &A) override {
23415dfd7cc4Ssstefan1     ChangeStatus Changed = ChangeStatus::UNCHANGED;
23425dfd7cc4Ssstefan1     const auto &ICVTrackingAA = A.getAAFor<AAICVTracker>(
23435b70c12fSJohannes Doerfert         *this, IRPosition::function(*getAnchorScope()), DepClassTy::REQUIRED);
23445dfd7cc4Ssstefan1 
23455dfd7cc4Ssstefan1     if (!ICVTrackingAA.isAssumedTracked())
23465dfd7cc4Ssstefan1       return indicatePessimisticFixpoint();
23475dfd7cc4Ssstefan1 
23485dfd7cc4Ssstefan1     for (InternalControlVar ICV : TrackableICVs) {
23495dfd7cc4Ssstefan1       Optional<Value *> &ReplVal = ICVReplacementValuesMap[ICV];
23505dfd7cc4Ssstefan1       Optional<Value *> UniqueICVValue;
23515dfd7cc4Ssstefan1 
23525dfd7cc4Ssstefan1       auto CheckReturnInst = [&](Instruction &I) {
23535dfd7cc4Ssstefan1         Optional<Value *> NewReplVal =
23545dfd7cc4Ssstefan1             ICVTrackingAA.getReplacementValue(ICV, &I, A);
23555dfd7cc4Ssstefan1 
23565dfd7cc4Ssstefan1         // If we found a second ICV value there is no unique returned value.
23575dfd7cc4Ssstefan1         if (UniqueICVValue.hasValue() && UniqueICVValue != NewReplVal)
23585dfd7cc4Ssstefan1           return false;
23595dfd7cc4Ssstefan1 
23605dfd7cc4Ssstefan1         UniqueICVValue = NewReplVal;
23615dfd7cc4Ssstefan1 
23625dfd7cc4Ssstefan1         return true;
23635dfd7cc4Ssstefan1       };
23645dfd7cc4Ssstefan1 
2365792aac98SJohannes Doerfert       bool UsedAssumedInformation = false;
23665dfd7cc4Ssstefan1       if (!A.checkForAllInstructions(CheckReturnInst, *this, {Instruction::Ret},
2367792aac98SJohannes Doerfert                                      UsedAssumedInformation,
23685dfd7cc4Ssstefan1                                      /* CheckBBLivenessOnly */ true))
23695dfd7cc4Ssstefan1         UniqueICVValue = nullptr;
23705dfd7cc4Ssstefan1 
23715dfd7cc4Ssstefan1       if (UniqueICVValue == ReplVal)
23725dfd7cc4Ssstefan1         continue;
23735dfd7cc4Ssstefan1 
23745dfd7cc4Ssstefan1       ReplVal = UniqueICVValue;
23755dfd7cc4Ssstefan1       Changed = ChangeStatus::CHANGED;
23765dfd7cc4Ssstefan1     }
23775dfd7cc4Ssstefan1 
23785dfd7cc4Ssstefan1     return Changed;
23795dfd7cc4Ssstefan1   }
23805dfd7cc4Ssstefan1 };
23815dfd7cc4Ssstefan1 
23825dfd7cc4Ssstefan1 struct AAICVTrackerCallSite : AAICVTracker {
23835dfd7cc4Ssstefan1   AAICVTrackerCallSite(const IRPosition &IRP, Attributor &A)
23845dfd7cc4Ssstefan1       : AAICVTracker(IRP, A) {}
23855dfd7cc4Ssstefan1 
23865dfd7cc4Ssstefan1   void initialize(Attributor &A) override {
23875dfd7cc4Ssstefan1     Function *F = getAnchorScope();
23885dfd7cc4Ssstefan1     if (!F || !A.isFunctionIPOAmendable(*F))
23895dfd7cc4Ssstefan1       indicatePessimisticFixpoint();
23905dfd7cc4Ssstefan1 
23915dfd7cc4Ssstefan1     // We only initialize this AA for getters, so we need to know which ICV it
23925dfd7cc4Ssstefan1     // gets.
23935dfd7cc4Ssstefan1     auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
23945dfd7cc4Ssstefan1     for (InternalControlVar ICV : TrackableICVs) {
23955dfd7cc4Ssstefan1       auto ICVInfo = OMPInfoCache.ICVs[ICV];
23965dfd7cc4Ssstefan1       auto &Getter = OMPInfoCache.RFIs[ICVInfo.Getter];
23975dfd7cc4Ssstefan1       if (Getter.Declaration == getAssociatedFunction()) {
23985dfd7cc4Ssstefan1         AssociatedICV = ICVInfo.Kind;
23995dfd7cc4Ssstefan1         return;
24005dfd7cc4Ssstefan1       }
24015dfd7cc4Ssstefan1     }
24025dfd7cc4Ssstefan1 
24035dfd7cc4Ssstefan1     /// Unknown ICV.
24045dfd7cc4Ssstefan1     indicatePessimisticFixpoint();
24055dfd7cc4Ssstefan1   }
24065dfd7cc4Ssstefan1 
24075dfd7cc4Ssstefan1   ChangeStatus manifest(Attributor &A) override {
24085dfd7cc4Ssstefan1     if (!ReplVal.hasValue() || !ReplVal.getValue())
24095dfd7cc4Ssstefan1       return ChangeStatus::UNCHANGED;
24105dfd7cc4Ssstefan1 
24115dfd7cc4Ssstefan1     A.changeValueAfterManifest(*getCtxI(), **ReplVal);
24125dfd7cc4Ssstefan1     A.deleteAfterManifest(*getCtxI());
24135dfd7cc4Ssstefan1 
24145dfd7cc4Ssstefan1     return ChangeStatus::CHANGED;
24155dfd7cc4Ssstefan1   }
24165dfd7cc4Ssstefan1 
24175dfd7cc4Ssstefan1   // FIXME: come up with better string.
24185dfd7cc4Ssstefan1   const std::string getAsStr() const override { return "ICVTrackerCallSite"; }
24195dfd7cc4Ssstefan1 
24205dfd7cc4Ssstefan1   // FIXME: come up with some stats.
24215dfd7cc4Ssstefan1   void trackStatistics() const override {}
24225dfd7cc4Ssstefan1 
24235dfd7cc4Ssstefan1   InternalControlVar AssociatedICV;
24245dfd7cc4Ssstefan1   Optional<Value *> ReplVal;
24255dfd7cc4Ssstefan1 
24265dfd7cc4Ssstefan1   ChangeStatus updateImpl(Attributor &A) override {
24275dfd7cc4Ssstefan1     const auto &ICVTrackingAA = A.getAAFor<AAICVTracker>(
24285b70c12fSJohannes Doerfert         *this, IRPosition::function(*getAnchorScope()), DepClassTy::REQUIRED);
24295dfd7cc4Ssstefan1 
24305dfd7cc4Ssstefan1     // We don't have any information, so we assume it changes the ICV.
24315dfd7cc4Ssstefan1     if (!ICVTrackingAA.isAssumedTracked())
24325dfd7cc4Ssstefan1       return indicatePessimisticFixpoint();
24335dfd7cc4Ssstefan1 
24345dfd7cc4Ssstefan1     Optional<Value *> NewReplVal =
24355dfd7cc4Ssstefan1         ICVTrackingAA.getReplacementValue(AssociatedICV, getCtxI(), A);
24365dfd7cc4Ssstefan1 
24375dfd7cc4Ssstefan1     if (ReplVal == NewReplVal)
24385dfd7cc4Ssstefan1       return ChangeStatus::UNCHANGED;
24395dfd7cc4Ssstefan1 
24405dfd7cc4Ssstefan1     ReplVal = NewReplVal;
24415dfd7cc4Ssstefan1     return ChangeStatus::CHANGED;
24425dfd7cc4Ssstefan1   }
24435dfd7cc4Ssstefan1 
24445dfd7cc4Ssstefan1   // Return the value with which associated value can be replaced for specific
24455dfd7cc4Ssstefan1   // \p ICV.
24465dfd7cc4Ssstefan1   Optional<Value *>
24475dfd7cc4Ssstefan1   getUniqueReplacementValue(InternalControlVar ICV) const override {
24485dfd7cc4Ssstefan1     return ReplVal;
24495dfd7cc4Ssstefan1   }
24505dfd7cc4Ssstefan1 };
24515dfd7cc4Ssstefan1 
24525dfd7cc4Ssstefan1 struct AAICVTrackerCallSiteReturned : AAICVTracker {
24535dfd7cc4Ssstefan1   AAICVTrackerCallSiteReturned(const IRPosition &IRP, Attributor &A)
24545dfd7cc4Ssstefan1       : AAICVTracker(IRP, A) {}
24555dfd7cc4Ssstefan1 
24565dfd7cc4Ssstefan1   // FIXME: come up with better string.
24575dfd7cc4Ssstefan1   const std::string getAsStr() const override {
24585dfd7cc4Ssstefan1     return "ICVTrackerCallSiteReturned";
24595dfd7cc4Ssstefan1   }
24605dfd7cc4Ssstefan1 
24615dfd7cc4Ssstefan1   // FIXME: come up with some stats.
24625dfd7cc4Ssstefan1   void trackStatistics() const override {}
24635dfd7cc4Ssstefan1 
24645dfd7cc4Ssstefan1   /// We don't manifest anything for this AA.
24655dfd7cc4Ssstefan1   ChangeStatus manifest(Attributor &A) override {
24665dfd7cc4Ssstefan1     return ChangeStatus::UNCHANGED;
24675dfd7cc4Ssstefan1   }
24685dfd7cc4Ssstefan1 
24695dfd7cc4Ssstefan1   // Map of ICV to their values at specific program point.
24705dfd7cc4Ssstefan1   EnumeratedArray<Optional<Value *>, InternalControlVar,
24715dfd7cc4Ssstefan1                   InternalControlVar::ICV___last>
24725dfd7cc4Ssstefan1       ICVReplacementValuesMap;
24735dfd7cc4Ssstefan1 
24745dfd7cc4Ssstefan1   /// Return the value with which associated value can be replaced for specific
24755dfd7cc4Ssstefan1   /// \p ICV.
24765dfd7cc4Ssstefan1   Optional<Value *>
24775dfd7cc4Ssstefan1   getUniqueReplacementValue(InternalControlVar ICV) const override {
24785dfd7cc4Ssstefan1     return ICVReplacementValuesMap[ICV];
24795dfd7cc4Ssstefan1   }
24805dfd7cc4Ssstefan1 
24815dfd7cc4Ssstefan1   ChangeStatus updateImpl(Attributor &A) override {
24825dfd7cc4Ssstefan1     ChangeStatus Changed = ChangeStatus::UNCHANGED;
24835dfd7cc4Ssstefan1     const auto &ICVTrackingAA = A.getAAFor<AAICVTracker>(
24845b70c12fSJohannes Doerfert         *this, IRPosition::returned(*getAssociatedFunction()),
24855b70c12fSJohannes Doerfert         DepClassTy::REQUIRED);
24865dfd7cc4Ssstefan1 
24875dfd7cc4Ssstefan1     // We don't have any information, so we assume it changes the ICV.
24885dfd7cc4Ssstefan1     if (!ICVTrackingAA.isAssumedTracked())
24895dfd7cc4Ssstefan1       return indicatePessimisticFixpoint();
24905dfd7cc4Ssstefan1 
24915dfd7cc4Ssstefan1     for (InternalControlVar ICV : TrackableICVs) {
24925dfd7cc4Ssstefan1       Optional<Value *> &ReplVal = ICVReplacementValuesMap[ICV];
24935dfd7cc4Ssstefan1       Optional<Value *> NewReplVal =
24945dfd7cc4Ssstefan1           ICVTrackingAA.getUniqueReplacementValue(ICV);
24955dfd7cc4Ssstefan1 
24965dfd7cc4Ssstefan1       if (ReplVal == NewReplVal)
24975dfd7cc4Ssstefan1         continue;
24985dfd7cc4Ssstefan1 
24995dfd7cc4Ssstefan1       ReplVal = NewReplVal;
25005dfd7cc4Ssstefan1       Changed = ChangeStatus::CHANGED;
25015dfd7cc4Ssstefan1     }
25025dfd7cc4Ssstefan1     return Changed;
25035dfd7cc4Ssstefan1   }
25049548b74aSJohannes Doerfert };
250518283125SJoseph Huber 
250618283125SJoseph Huber struct AAExecutionDomainFunction : public AAExecutionDomain {
250718283125SJoseph Huber   AAExecutionDomainFunction(const IRPosition &IRP, Attributor &A)
250818283125SJoseph Huber       : AAExecutionDomain(IRP, A) {}
250918283125SJoseph Huber 
251018283125SJoseph Huber   const std::string getAsStr() const override {
251118283125SJoseph Huber     return "[AAExecutionDomain] " + std::to_string(SingleThreadedBBs.size()) +
251218283125SJoseph Huber            "/" + std::to_string(NumBBs) + " BBs thread 0 only.";
251318283125SJoseph Huber   }
251418283125SJoseph Huber 
251518283125SJoseph Huber   /// See AbstractAttribute::trackStatistics().
251618283125SJoseph Huber   void trackStatistics() const override {}
251718283125SJoseph Huber 
251818283125SJoseph Huber   void initialize(Attributor &A) override {
251918283125SJoseph Huber     Function *F = getAnchorScope();
252018283125SJoseph Huber     for (const auto &BB : *F)
252118283125SJoseph Huber       SingleThreadedBBs.insert(&BB);
252218283125SJoseph Huber     NumBBs = SingleThreadedBBs.size();
252318283125SJoseph Huber   }
252418283125SJoseph Huber 
252518283125SJoseph Huber   ChangeStatus manifest(Attributor &A) override {
252618283125SJoseph Huber     LLVM_DEBUG({
252718283125SJoseph Huber       for (const BasicBlock *BB : SingleThreadedBBs)
252818283125SJoseph Huber         dbgs() << TAG << " Basic block @" << getAnchorScope()->getName() << " "
252918283125SJoseph Huber                << BB->getName() << " is executed by a single thread.\n";
253018283125SJoseph Huber     });
253118283125SJoseph Huber     return ChangeStatus::UNCHANGED;
253218283125SJoseph Huber   }
253318283125SJoseph Huber 
253418283125SJoseph Huber   ChangeStatus updateImpl(Attributor &A) override;
253518283125SJoseph Huber 
253618283125SJoseph Huber   /// Check if an instruction is executed by a single thread.
25379a23e673SJohannes Doerfert   bool isExecutedByInitialThreadOnly(const Instruction &I) const override {
25389a23e673SJohannes Doerfert     return isExecutedByInitialThreadOnly(*I.getParent());
253918283125SJoseph Huber   }
254018283125SJoseph Huber 
25419a23e673SJohannes Doerfert   bool isExecutedByInitialThreadOnly(const BasicBlock &BB) const override {
25421cfdcae6SJoseph Huber     return isValidState() && SingleThreadedBBs.contains(&BB);
254318283125SJoseph Huber   }
254418283125SJoseph Huber 
254518283125SJoseph Huber   /// Set of basic blocks that are executed by a single thread.
25469f04a0eaSJohannes Doerfert   SmallSetVector<const BasicBlock *, 16> SingleThreadedBBs;
254718283125SJoseph Huber 
254818283125SJoseph Huber   /// Total number of basic blocks in this function.
254918283125SJoseph Huber   long unsigned NumBBs;
255018283125SJoseph Huber };
255118283125SJoseph Huber 
255218283125SJoseph Huber ChangeStatus AAExecutionDomainFunction::updateImpl(Attributor &A) {
255318283125SJoseph Huber   Function *F = getAnchorScope();
255418283125SJoseph Huber   ReversePostOrderTraversal<Function *> RPOT(F);
255518283125SJoseph Huber   auto NumSingleThreadedBBs = SingleThreadedBBs.size();
255618283125SJoseph Huber 
255718283125SJoseph Huber   bool AllCallSitesKnown;
255818283125SJoseph Huber   auto PredForCallSite = [&](AbstractCallSite ACS) {
255918283125SJoseph Huber     const auto &ExecutionDomainAA = A.getAAFor<AAExecutionDomain>(
256018283125SJoseph Huber         *this, IRPosition::function(*ACS.getInstruction()->getFunction()),
256118283125SJoseph Huber         DepClassTy::REQUIRED);
25621cfdcae6SJoseph Huber     return ACS.isDirectCall() &&
25631cfdcae6SJoseph Huber            ExecutionDomainAA.isExecutedByInitialThreadOnly(
25649a23e673SJohannes Doerfert                *ACS.getInstruction());
256518283125SJoseph Huber   };
256618283125SJoseph Huber 
256718283125SJoseph Huber   if (!A.checkForAllCallSites(PredForCallSite, *this,
256818283125SJoseph Huber                               /* RequiresAllCallSites */ true,
256918283125SJoseph Huber                               AllCallSitesKnown))
25709f04a0eaSJohannes Doerfert     SingleThreadedBBs.remove(&F->getEntryBlock());
257118283125SJoseph Huber 
2572e2cfbfccSJohannes Doerfert   auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
2573e2cfbfccSJohannes Doerfert   auto &RFI = OMPInfoCache.RFIs[OMPRTL___kmpc_target_init];
2574e2cfbfccSJohannes Doerfert 
257527905eebSJoseph Huber   // Check if the edge into the successor block contains a condition that only
257627905eebSJoseph Huber   // lets the main thread execute it.
25776fc51c9fSJoseph Huber   auto IsInitialThreadOnly = [&](BranchInst *Edge, BasicBlock *SuccessorBB) {
257818283125SJoseph Huber     if (!Edge || !Edge->isConditional())
257918283125SJoseph Huber       return false;
258018283125SJoseph Huber     if (Edge->getSuccessor(0) != SuccessorBB)
258118283125SJoseph Huber       return false;
258218283125SJoseph Huber 
258318283125SJoseph Huber     auto *Cmp = dyn_cast<CmpInst>(Edge->getCondition());
258418283125SJoseph Huber     if (!Cmp || !Cmp->isTrueWhenEqual() || !Cmp->isEquality())
258518283125SJoseph Huber       return false;
258618283125SJoseph Huber 
258718283125SJoseph Huber     ConstantInt *C = dyn_cast<ConstantInt>(Cmp->getOperand(1));
2588e2cfbfccSJohannes Doerfert     if (!C)
258918283125SJoseph Huber       return false;
259018283125SJoseph Huber 
2591e2cfbfccSJohannes Doerfert     // Match: -1 == __kmpc_target_init (for non-SPMD kernels only!)
2592e2cfbfccSJohannes Doerfert     if (C->isAllOnesValue()) {
2593e2cfbfccSJohannes Doerfert       auto *CB = dyn_cast<CallBase>(Cmp->getOperand(0));
2594c4b1fe05SJohannes Doerfert       CB = CB ? OpenMPOpt::getCallIfRegularCall(*CB, &RFI) : nullptr;
2595c4b1fe05SJohannes Doerfert       if (!CB)
2596e2cfbfccSJohannes Doerfert         return false;
2597423d34f7SShilei Tian       const int InitModeArgNo = 1;
2598423d34f7SShilei Tian       auto *ModeCI = dyn_cast<ConstantInt>(CB->getOperand(InitModeArgNo));
2599423d34f7SShilei Tian       return ModeCI && (ModeCI->getSExtValue() & OMP_TGT_EXEC_MODE_GENERIC);
2600e2cfbfccSJohannes Doerfert     }
260118283125SJoseph Huber 
260227905eebSJoseph Huber     if (C->isZero()) {
260327905eebSJoseph Huber       // Match: 0 == llvm.nvvm.read.ptx.sreg.tid.x()
260427905eebSJoseph Huber       if (auto *II = dyn_cast<IntrinsicInst>(Cmp->getOperand(0)))
260527905eebSJoseph Huber         if (II->getIntrinsicID() == Intrinsic::nvvm_read_ptx_sreg_tid_x)
260627905eebSJoseph Huber           return true;
260727905eebSJoseph Huber 
260827905eebSJoseph Huber       // Match: 0 == llvm.amdgcn.workitem.id.x()
260927905eebSJoseph Huber       if (auto *II = dyn_cast<IntrinsicInst>(Cmp->getOperand(0)))
261027905eebSJoseph Huber         if (II->getIntrinsicID() == Intrinsic::amdgcn_workitem_id_x)
261127905eebSJoseph Huber           return true;
261227905eebSJoseph Huber     }
261327905eebSJoseph Huber 
261418283125SJoseph Huber     return false;
261518283125SJoseph Huber   };
261618283125SJoseph Huber 
261718283125SJoseph Huber   // Merge all the predecessor states into the current basic block. A basic
261818283125SJoseph Huber   // block is executed by a single thread if all of its predecessors are.
261918283125SJoseph Huber   auto MergePredecessorStates = [&](BasicBlock *BB) {
262098007313SKazu Hirata     if (pred_empty(BB))
262118283125SJoseph Huber       return SingleThreadedBBs.contains(BB);
262218283125SJoseph Huber 
26236fc51c9fSJoseph Huber     bool IsInitialThread = true;
262498007313SKazu Hirata     for (BasicBlock *PredBB : predecessors(BB)) {
262598007313SKazu Hirata       if (!IsInitialThreadOnly(dyn_cast<BranchInst>(PredBB->getTerminator()),
262618283125SJoseph Huber                                BB))
262798007313SKazu Hirata         IsInitialThread &= SingleThreadedBBs.contains(PredBB);
262818283125SJoseph Huber     }
262918283125SJoseph Huber 
26306fc51c9fSJoseph Huber     return IsInitialThread;
263118283125SJoseph Huber   };
263218283125SJoseph Huber 
263318283125SJoseph Huber   for (auto *BB : RPOT) {
263418283125SJoseph Huber     if (!MergePredecessorStates(BB))
26359f04a0eaSJohannes Doerfert       SingleThreadedBBs.remove(BB);
263618283125SJoseph Huber   }
263718283125SJoseph Huber 
263818283125SJoseph Huber   return (NumSingleThreadedBBs == SingleThreadedBBs.size())
263918283125SJoseph Huber              ? ChangeStatus::UNCHANGED
264018283125SJoseph Huber              : ChangeStatus::CHANGED;
264118283125SJoseph Huber }
264218283125SJoseph Huber 
26436fc51c9fSJoseph Huber /// Try to replace memory allocation calls called by a single thread with a
26446fc51c9fSJoseph Huber /// static buffer of shared memory.
26456fc51c9fSJoseph Huber struct AAHeapToShared : public StateWrapper<BooleanState, AbstractAttribute> {
26466fc51c9fSJoseph Huber   using Base = StateWrapper<BooleanState, AbstractAttribute>;
26476fc51c9fSJoseph Huber   AAHeapToShared(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
26486fc51c9fSJoseph Huber 
26496fc51c9fSJoseph Huber   /// Create an abstract attribute view for the position \p IRP.
26506fc51c9fSJoseph Huber   static AAHeapToShared &createForPosition(const IRPosition &IRP,
26516fc51c9fSJoseph Huber                                            Attributor &A);
26526fc51c9fSJoseph Huber 
2653f8c40ed8SGiorgis Georgakoudis   /// Returns true if HeapToShared conversion is assumed to be possible.
2654f8c40ed8SGiorgis Georgakoudis   virtual bool isAssumedHeapToShared(CallBase &CB) const = 0;
2655f8c40ed8SGiorgis Georgakoudis 
2656f8c40ed8SGiorgis Georgakoudis   /// Returns true if HeapToShared conversion is assumed and the CB is a
2657f8c40ed8SGiorgis Georgakoudis   /// callsite to a free operation to be removed.
2658f8c40ed8SGiorgis Georgakoudis   virtual bool isAssumedHeapToSharedRemovedFree(CallBase &CB) const = 0;
2659f8c40ed8SGiorgis Georgakoudis 
26606fc51c9fSJoseph Huber   /// See AbstractAttribute::getName().
26616fc51c9fSJoseph Huber   const std::string getName() const override { return "AAHeapToShared"; }
26626fc51c9fSJoseph Huber 
26636fc51c9fSJoseph Huber   /// See AbstractAttribute::getIdAddr().
26646fc51c9fSJoseph Huber   const char *getIdAddr() const override { return &ID; }
26656fc51c9fSJoseph Huber 
26666fc51c9fSJoseph Huber   /// This function should return true if the type of the \p AA is
26676fc51c9fSJoseph Huber   /// AAHeapToShared.
26686fc51c9fSJoseph Huber   static bool classof(const AbstractAttribute *AA) {
26696fc51c9fSJoseph Huber     return (AA->getIdAddr() == &ID);
26706fc51c9fSJoseph Huber   }
26716fc51c9fSJoseph Huber 
26726fc51c9fSJoseph Huber   /// Unique ID (due to the unique address)
26736fc51c9fSJoseph Huber   static const char ID;
26746fc51c9fSJoseph Huber };
26756fc51c9fSJoseph Huber 
26766fc51c9fSJoseph Huber struct AAHeapToSharedFunction : public AAHeapToShared {
26776fc51c9fSJoseph Huber   AAHeapToSharedFunction(const IRPosition &IRP, Attributor &A)
26786fc51c9fSJoseph Huber       : AAHeapToShared(IRP, A) {}
26796fc51c9fSJoseph Huber 
26806fc51c9fSJoseph Huber   const std::string getAsStr() const override {
26816fc51c9fSJoseph Huber     return "[AAHeapToShared] " + std::to_string(MallocCalls.size()) +
26826fc51c9fSJoseph Huber            " malloc calls eligible.";
26836fc51c9fSJoseph Huber   }
26846fc51c9fSJoseph Huber 
26856fc51c9fSJoseph Huber   /// See AbstractAttribute::trackStatistics().
26866fc51c9fSJoseph Huber   void trackStatistics() const override {}
26876fc51c9fSJoseph Huber 
2688f8c40ed8SGiorgis Georgakoudis   /// This functions finds free calls that will be removed by the
2689f8c40ed8SGiorgis Georgakoudis   /// HeapToShared transformation.
2690f8c40ed8SGiorgis Georgakoudis   void findPotentialRemovedFreeCalls(Attributor &A) {
2691f8c40ed8SGiorgis Georgakoudis     auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
2692f8c40ed8SGiorgis Georgakoudis     auto &FreeRFI = OMPInfoCache.RFIs[OMPRTL___kmpc_free_shared];
2693f8c40ed8SGiorgis Georgakoudis 
2694f8c40ed8SGiorgis Georgakoudis     PotentialRemovedFreeCalls.clear();
2695f8c40ed8SGiorgis Georgakoudis     // Update free call users of found malloc calls.
2696f8c40ed8SGiorgis Georgakoudis     for (CallBase *CB : MallocCalls) {
2697f8c40ed8SGiorgis Georgakoudis       SmallVector<CallBase *, 4> FreeCalls;
2698f8c40ed8SGiorgis Georgakoudis       for (auto *U : CB->users()) {
2699f8c40ed8SGiorgis Georgakoudis         CallBase *C = dyn_cast<CallBase>(U);
2700f8c40ed8SGiorgis Georgakoudis         if (C && C->getCalledFunction() == FreeRFI.Declaration)
2701f8c40ed8SGiorgis Georgakoudis           FreeCalls.push_back(C);
2702f8c40ed8SGiorgis Georgakoudis       }
2703f8c40ed8SGiorgis Georgakoudis 
2704f8c40ed8SGiorgis Georgakoudis       if (FreeCalls.size() != 1)
2705f8c40ed8SGiorgis Georgakoudis         continue;
2706f8c40ed8SGiorgis Georgakoudis 
2707f8c40ed8SGiorgis Georgakoudis       PotentialRemovedFreeCalls.insert(FreeCalls.front());
2708f8c40ed8SGiorgis Georgakoudis     }
2709f8c40ed8SGiorgis Georgakoudis   }
2710f8c40ed8SGiorgis Georgakoudis 
27116fc51c9fSJoseph Huber   void initialize(Attributor &A) override {
27126fc51c9fSJoseph Huber     auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
27136fc51c9fSJoseph Huber     auto &RFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
27146fc51c9fSJoseph Huber 
27156fc51c9fSJoseph Huber     for (User *U : RFI.Declaration->users())
27166fc51c9fSJoseph Huber       if (CallBase *CB = dyn_cast<CallBase>(U))
27176fc51c9fSJoseph Huber         MallocCalls.insert(CB);
2718f8c40ed8SGiorgis Georgakoudis 
2719f8c40ed8SGiorgis Georgakoudis     findPotentialRemovedFreeCalls(A);
2720f8c40ed8SGiorgis Georgakoudis   }
2721f8c40ed8SGiorgis Georgakoudis 
2722eaab880eSGiorgis Georgakoudis   bool isAssumedHeapToShared(CallBase &CB) const override {
2723f8c40ed8SGiorgis Georgakoudis     return isValidState() && MallocCalls.count(&CB);
2724f8c40ed8SGiorgis Georgakoudis   }
2725f8c40ed8SGiorgis Georgakoudis 
2726eaab880eSGiorgis Georgakoudis   bool isAssumedHeapToSharedRemovedFree(CallBase &CB) const override {
2727f8c40ed8SGiorgis Georgakoudis     return isValidState() && PotentialRemovedFreeCalls.count(&CB);
27286fc51c9fSJoseph Huber   }
27296fc51c9fSJoseph Huber 
27306fc51c9fSJoseph Huber   ChangeStatus manifest(Attributor &A) override {
27316fc51c9fSJoseph Huber     if (MallocCalls.empty())
27326fc51c9fSJoseph Huber       return ChangeStatus::UNCHANGED;
27336fc51c9fSJoseph Huber 
27346fc51c9fSJoseph Huber     auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
27356fc51c9fSJoseph Huber     auto &FreeCall = OMPInfoCache.RFIs[OMPRTL___kmpc_free_shared];
27366fc51c9fSJoseph Huber 
27376fc51c9fSJoseph Huber     Function *F = getAnchorScope();
27386fc51c9fSJoseph Huber     auto *HS = A.lookupAAFor<AAHeapToStack>(IRPosition::function(*F), this,
27396fc51c9fSJoseph Huber                                             DepClassTy::OPTIONAL);
27406fc51c9fSJoseph Huber 
27416fc51c9fSJoseph Huber     ChangeStatus Changed = ChangeStatus::UNCHANGED;
27426fc51c9fSJoseph Huber     for (CallBase *CB : MallocCalls) {
27436fc51c9fSJoseph Huber       // Skip replacing this if HeapToStack has already claimed it.
2744c1c1fe93SJohannes Doerfert       if (HS && HS->isAssumedHeapToStack(*CB))
27456fc51c9fSJoseph Huber         continue;
27466fc51c9fSJoseph Huber 
27476fc51c9fSJoseph Huber       // Find the unique free call to remove it.
27486fc51c9fSJoseph Huber       SmallVector<CallBase *, 4> FreeCalls;
27496fc51c9fSJoseph Huber       for (auto *U : CB->users()) {
27506fc51c9fSJoseph Huber         CallBase *C = dyn_cast<CallBase>(U);
27516fc51c9fSJoseph Huber         if (C && C->getCalledFunction() == FreeCall.Declaration)
27526fc51c9fSJoseph Huber           FreeCalls.push_back(C);
27536fc51c9fSJoseph Huber       }
27546fc51c9fSJoseph Huber       if (FreeCalls.size() != 1)
27556fc51c9fSJoseph Huber         continue;
27566fc51c9fSJoseph Huber 
2757274359cfSSimon Pilgrim       auto *AllocSize = cast<ConstantInt>(CB->getArgOperand(0));
27586fc51c9fSJoseph Huber 
275913d8f000SJoseph Huber       LLVM_DEBUG(dbgs() << TAG << "Replace globalization call " << *CB
276013d8f000SJoseph Huber                         << " with " << AllocSize->getZExtValue()
27616fc51c9fSJoseph Huber                         << " bytes of shared memory\n");
27626fc51c9fSJoseph Huber 
27636fc51c9fSJoseph Huber       // Create a new shared memory buffer of the same size as the allocation
27646fc51c9fSJoseph Huber       // and replace all the uses of the original allocation with it.
27656fc51c9fSJoseph Huber       Module *M = CB->getModule();
27666fc51c9fSJoseph Huber       Type *Int8Ty = Type::getInt8Ty(M->getContext());
27676fc51c9fSJoseph Huber       Type *Int8ArrTy = ArrayType::get(Int8Ty, AllocSize->getZExtValue());
27686fc51c9fSJoseph Huber       auto *SharedMem = new GlobalVariable(
27696fc51c9fSJoseph Huber           *M, Int8ArrTy, /* IsConstant */ false, GlobalValue::InternalLinkage,
27706fc51c9fSJoseph Huber           UndefValue::get(Int8ArrTy), CB->getName(), nullptr,
27716fc51c9fSJoseph Huber           GlobalValue::NotThreadLocal,
27726fc51c9fSJoseph Huber           static_cast<unsigned>(AddressSpace::Shared));
27736fc51c9fSJoseph Huber       auto *NewBuffer =
27746fc51c9fSJoseph Huber           ConstantExpr::getPointerCast(SharedMem, Int8Ty->getPointerTo());
27756fc51c9fSJoseph Huber 
277630e36c9bSJoseph Huber       auto Remark = [&](OptimizationRemark OR) {
277730e36c9bSJoseph Huber         return OR << "Replaced globalized variable with "
277830e36c9bSJoseph Huber                   << ore::NV("SharedMemory", AllocSize->getZExtValue())
277930e36c9bSJoseph Huber                   << ((AllocSize->getZExtValue() != 1) ? " bytes " : " byte ")
2780eef6601bSJoseph Huber                   << "of shared memory.";
278130e36c9bSJoseph Huber       };
27822c31d5ebSJoseph Huber       A.emitRemark<OptimizationRemark>(CB, "OMP111", Remark);
278330e36c9bSJoseph Huber 
27846e220296SJoseph Huber       MaybeAlign Alignment = CB->getRetAlign();
27856e220296SJoseph Huber       assert(Alignment &&
27866e220296SJoseph Huber              "HeapToShared on allocation without alignment attribute");
27876e220296SJoseph Huber       SharedMem->setAlignment(MaybeAlign(Alignment));
27886fc51c9fSJoseph Huber 
27896fc51c9fSJoseph Huber       A.changeValueAfterManifest(*CB, *NewBuffer);
27906fc51c9fSJoseph Huber       A.deleteAfterManifest(*CB);
27916fc51c9fSJoseph Huber       A.deleteAfterManifest(*FreeCalls.front());
27926fc51c9fSJoseph Huber 
27936fc51c9fSJoseph Huber       NumBytesMovedToSharedMemory += AllocSize->getZExtValue();
27946fc51c9fSJoseph Huber       Changed = ChangeStatus::CHANGED;
27956fc51c9fSJoseph Huber     }
27966fc51c9fSJoseph Huber 
27976fc51c9fSJoseph Huber     return Changed;
27986fc51c9fSJoseph Huber   }
27996fc51c9fSJoseph Huber 
28006fc51c9fSJoseph Huber   ChangeStatus updateImpl(Attributor &A) override {
28016fc51c9fSJoseph Huber     auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
28026fc51c9fSJoseph Huber     auto &RFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
28036fc51c9fSJoseph Huber     Function *F = getAnchorScope();
28046fc51c9fSJoseph Huber 
28056fc51c9fSJoseph Huber     auto NumMallocCalls = MallocCalls.size();
28066fc51c9fSJoseph Huber 
28076fc51c9fSJoseph Huber     // Only consider malloc calls executed by a single thread with a constant.
28086fc51c9fSJoseph Huber     for (User *U : RFI.Declaration->users()) {
28096fc51c9fSJoseph Huber       const auto &ED = A.getAAFor<AAExecutionDomain>(
28106fc51c9fSJoseph Huber           *this, IRPosition::function(*F), DepClassTy::REQUIRED);
28116fc51c9fSJoseph Huber       if (CallBase *CB = dyn_cast<CallBase>(U))
2812d243cbf8SKazu Hirata         if (!isa<ConstantInt>(CB->getArgOperand(0)) ||
28136fc51c9fSJoseph Huber             !ED.isExecutedByInitialThreadOnly(*CB))
2814ba70f3a5SJohannes Doerfert           MallocCalls.remove(CB);
28156fc51c9fSJoseph Huber     }
28166fc51c9fSJoseph Huber 
2817f8c40ed8SGiorgis Georgakoudis     findPotentialRemovedFreeCalls(A);
2818f8c40ed8SGiorgis Georgakoudis 
28196fc51c9fSJoseph Huber     if (NumMallocCalls != MallocCalls.size())
28206fc51c9fSJoseph Huber       return ChangeStatus::CHANGED;
28216fc51c9fSJoseph Huber 
28226fc51c9fSJoseph Huber     return ChangeStatus::UNCHANGED;
28236fc51c9fSJoseph Huber   }
28246fc51c9fSJoseph Huber 
28256fc51c9fSJoseph Huber   /// Collection of all malloc calls in a function.
2826ba70f3a5SJohannes Doerfert   SmallSetVector<CallBase *, 4> MallocCalls;
2827f8c40ed8SGiorgis Georgakoudis   /// Collection of potentially removed free calls in a function.
2828f8c40ed8SGiorgis Georgakoudis   SmallPtrSet<CallBase *, 4> PotentialRemovedFreeCalls;
28296fc51c9fSJoseph Huber };
28306fc51c9fSJoseph Huber 
2831d9659bf6SJohannes Doerfert struct AAKernelInfo : public StateWrapper<KernelInfoState, AbstractAttribute> {
2832d9659bf6SJohannes Doerfert   using Base = StateWrapper<KernelInfoState, AbstractAttribute>;
2833d9659bf6SJohannes Doerfert   AAKernelInfo(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
2834d9659bf6SJohannes Doerfert 
2835d9659bf6SJohannes Doerfert   /// Statistics are tracked as part of manifest for now.
2836d9659bf6SJohannes Doerfert   void trackStatistics() const override {}
2837d9659bf6SJohannes Doerfert 
2838d9659bf6SJohannes Doerfert   /// See AbstractAttribute::getAsStr()
2839d9659bf6SJohannes Doerfert   const std::string getAsStr() const override {
2840d9659bf6SJohannes Doerfert     if (!isValidState())
2841d9659bf6SJohannes Doerfert       return "<invalid>";
2842514c033dSJohannes Doerfert     return std::string(SPMDCompatibilityTracker.isAssumed() ? "SPMD"
2843514c033dSJohannes Doerfert                                                             : "generic") +
2844514c033dSJohannes Doerfert            std::string(SPMDCompatibilityTracker.isAtFixpoint() ? " [FIX]"
2845514c033dSJohannes Doerfert                                                                : "") +
2846d9659bf6SJohannes Doerfert            std::string(" #PRs: ") +
2847c6457dcaSJohannes Doerfert            (ReachedKnownParallelRegions.isValidState()
2848c6457dcaSJohannes Doerfert                 ? std::to_string(ReachedKnownParallelRegions.size())
2849c6457dcaSJohannes Doerfert                 : "<invalid>") +
2850d9659bf6SJohannes Doerfert            ", #Unknown PRs: " +
2851c6457dcaSJohannes Doerfert            (ReachedUnknownParallelRegions.isValidState()
2852c6457dcaSJohannes Doerfert                 ? std::to_string(ReachedUnknownParallelRegions.size())
2853c6457dcaSJohannes Doerfert                 : "<invalid>") +
28540a16c560SJohannes Doerfert            ", #Reaching Kernels: " +
28550a16c560SJohannes Doerfert            (ReachingKernelEntries.isValidState()
28560a16c560SJohannes Doerfert                 ? std::to_string(ReachingKernelEntries.size())
28570a16c560SJohannes Doerfert                 : "<invalid>");
2858d9659bf6SJohannes Doerfert   }
2859d9659bf6SJohannes Doerfert 
2860d9659bf6SJohannes Doerfert   /// Create an abstract attribute biew for the position \p IRP.
2861d9659bf6SJohannes Doerfert   static AAKernelInfo &createForPosition(const IRPosition &IRP, Attributor &A);
2862d9659bf6SJohannes Doerfert 
2863d9659bf6SJohannes Doerfert   /// See AbstractAttribute::getName()
2864d9659bf6SJohannes Doerfert   const std::string getName() const override { return "AAKernelInfo"; }
2865d9659bf6SJohannes Doerfert 
2866d9659bf6SJohannes Doerfert   /// See AbstractAttribute::getIdAddr()
2867d9659bf6SJohannes Doerfert   const char *getIdAddr() const override { return &ID; }
2868d9659bf6SJohannes Doerfert 
2869d9659bf6SJohannes Doerfert   /// This function should return true if the type of the \p AA is AAKernelInfo
2870d9659bf6SJohannes Doerfert   static bool classof(const AbstractAttribute *AA) {
2871d9659bf6SJohannes Doerfert     return (AA->getIdAddr() == &ID);
2872d9659bf6SJohannes Doerfert   }
2873d9659bf6SJohannes Doerfert 
2874d9659bf6SJohannes Doerfert   static const char ID;
2875d9659bf6SJohannes Doerfert };
2876d9659bf6SJohannes Doerfert 
2877d9659bf6SJohannes Doerfert /// The function kernel info abstract attribute, basically, what can we say
2878d9659bf6SJohannes Doerfert /// about a function with regards to the KernelInfoState.
2879d9659bf6SJohannes Doerfert struct AAKernelInfoFunction : AAKernelInfo {
2880d9659bf6SJohannes Doerfert   AAKernelInfoFunction(const IRPosition &IRP, Attributor &A)
2881d9659bf6SJohannes Doerfert       : AAKernelInfo(IRP, A) {}
2882d9659bf6SJohannes Doerfert 
288329a3e3ddSGiorgis Georgakoudis   SmallPtrSet<Instruction *, 4> GuardedInstructions;
288429a3e3ddSGiorgis Georgakoudis 
288529a3e3ddSGiorgis Georgakoudis   SmallPtrSetImpl<Instruction *> &getGuardedInstructions() {
288629a3e3ddSGiorgis Georgakoudis     return GuardedInstructions;
288729a3e3ddSGiorgis Georgakoudis   }
288829a3e3ddSGiorgis Georgakoudis 
2889d9659bf6SJohannes Doerfert   /// See AbstractAttribute::initialize(...).
2890d9659bf6SJohannes Doerfert   void initialize(Attributor &A) override {
2891d9659bf6SJohannes Doerfert     // This is a high-level transform that might change the constant arguments
2892d9659bf6SJohannes Doerfert     // of the init and dinit calls. We need to tell the Attributor about this
2893d9659bf6SJohannes Doerfert     // to avoid other parts using the current constant value for simpliication.
2894d9659bf6SJohannes Doerfert     auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
2895d9659bf6SJohannes Doerfert 
2896d9659bf6SJohannes Doerfert     Function *Fn = getAnchorScope();
2897d9659bf6SJohannes Doerfert     if (!OMPInfoCache.Kernels.count(Fn))
2898d9659bf6SJohannes Doerfert       return;
2899d9659bf6SJohannes Doerfert 
2900ca662297SShilei Tian     // Add itself to the reaching kernel and set IsKernelEntry.
2901ca662297SShilei Tian     ReachingKernelEntries.insert(Fn);
2902ca662297SShilei Tian     IsKernelEntry = true;
2903ca662297SShilei Tian 
2904d9659bf6SJohannes Doerfert     OMPInformationCache::RuntimeFunctionInfo &InitRFI =
2905d9659bf6SJohannes Doerfert         OMPInfoCache.RFIs[OMPRTL___kmpc_target_init];
2906d9659bf6SJohannes Doerfert     OMPInformationCache::RuntimeFunctionInfo &DeinitRFI =
2907d9659bf6SJohannes Doerfert         OMPInfoCache.RFIs[OMPRTL___kmpc_target_deinit];
2908d9659bf6SJohannes Doerfert 
2909d9659bf6SJohannes Doerfert     // For kernels we perform more initialization work, first we find the init
2910d9659bf6SJohannes Doerfert     // and deinit calls.
2911d9659bf6SJohannes Doerfert     auto StoreCallBase = [](Use &U,
2912d9659bf6SJohannes Doerfert                             OMPInformationCache::RuntimeFunctionInfo &RFI,
2913d9659bf6SJohannes Doerfert                             CallBase *&Storage) {
2914d9659bf6SJohannes Doerfert       CallBase *CB = OpenMPOpt::getCallIfRegularCall(U, &RFI);
2915d9659bf6SJohannes Doerfert       assert(CB &&
2916d9659bf6SJohannes Doerfert              "Unexpected use of __kmpc_target_init or __kmpc_target_deinit!");
2917d9659bf6SJohannes Doerfert       assert(!Storage &&
2918d9659bf6SJohannes Doerfert              "Multiple uses of __kmpc_target_init or __kmpc_target_deinit!");
2919d9659bf6SJohannes Doerfert       Storage = CB;
2920d9659bf6SJohannes Doerfert       return false;
2921d9659bf6SJohannes Doerfert     };
2922d9659bf6SJohannes Doerfert     InitRFI.foreachUse(
2923d9659bf6SJohannes Doerfert         [&](Use &U, Function &) {
2924d9659bf6SJohannes Doerfert           StoreCallBase(U, InitRFI, KernelInitCB);
2925d9659bf6SJohannes Doerfert           return false;
2926d9659bf6SJohannes Doerfert         },
2927d9659bf6SJohannes Doerfert         Fn);
2928d9659bf6SJohannes Doerfert     DeinitRFI.foreachUse(
2929d9659bf6SJohannes Doerfert         [&](Use &U, Function &) {
2930d9659bf6SJohannes Doerfert           StoreCallBase(U, DeinitRFI, KernelDeinitCB);
2931d9659bf6SJohannes Doerfert           return false;
2932d9659bf6SJohannes Doerfert         },
2933d9659bf6SJohannes Doerfert         Fn);
2934d9659bf6SJohannes Doerfert 
293558f93264SJoseph Huber     // Ignore kernels without initializers such as global constructors.
293658f93264SJoseph Huber     if (!KernelInitCB || !KernelDeinitCB) {
293758f93264SJoseph Huber       indicateOptimisticFixpoint();
293858f93264SJoseph Huber       return;
293958f93264SJoseph Huber     }
2940d9659bf6SJohannes Doerfert 
2941514c033dSJohannes Doerfert     // For kernels we might need to initialize/finalize the IsSPMD state and
2942514c033dSJohannes Doerfert     // we need to register a simplification callback so that the Attributor
2943514c033dSJohannes Doerfert     // knows the constant arguments to __kmpc_target_init and
2944d9659bf6SJohannes Doerfert     // __kmpc_target_deinit might actually change.
2945d9659bf6SJohannes Doerfert 
2946d9659bf6SJohannes Doerfert     Attributor::SimplifictionCallbackTy StateMachineSimplifyCB =
2947d9659bf6SJohannes Doerfert         [&](const IRPosition &IRP, const AbstractAttribute *AA,
2948d9659bf6SJohannes Doerfert             bool &UsedAssumedInformation) -> Optional<Value *> {
2949d9659bf6SJohannes Doerfert       // IRP represents the "use generic state machine" argument of an
2950d9659bf6SJohannes Doerfert       // __kmpc_target_init call. We will answer this one with the internal
2951d9659bf6SJohannes Doerfert       // state. As long as we are not in an invalid state, we will create a
2952d9659bf6SJohannes Doerfert       // custom state machine so the value should be a `i1 false`. If we are
2953d9659bf6SJohannes Doerfert       // in an invalid state, we won't change the value that is in the IR.
2954e6e440aeSJohannes Doerfert       if (!ReachedKnownParallelRegions.isValidState())
2955d9659bf6SJohannes Doerfert         return nullptr;
2956e0c5d83aSJohannes Doerfert       // If we have disabled state machine rewrites, don't make a custom one.
2957e0c5d83aSJohannes Doerfert       if (DisableOpenMPOptStateMachineRewrite)
2958e0c5d83aSJohannes Doerfert         return nullptr;
2959d9659bf6SJohannes Doerfert       if (AA)
2960d9659bf6SJohannes Doerfert         A.recordDependence(*this, *AA, DepClassTy::OPTIONAL);
2961d9659bf6SJohannes Doerfert       UsedAssumedInformation = !isAtFixpoint();
2962d9659bf6SJohannes Doerfert       auto *FalseVal =
29632aed0813SKazu Hirata           ConstantInt::getBool(IRP.getAnchorValue().getContext(), false);
2964d9659bf6SJohannes Doerfert       return FalseVal;
2965d9659bf6SJohannes Doerfert     };
2966d9659bf6SJohannes Doerfert 
2967423d34f7SShilei Tian     Attributor::SimplifictionCallbackTy ModeSimplifyCB =
2968514c033dSJohannes Doerfert         [&](const IRPosition &IRP, const AbstractAttribute *AA,
2969514c033dSJohannes Doerfert             bool &UsedAssumedInformation) -> Optional<Value *> {
2970514c033dSJohannes Doerfert       // IRP represents the "SPMDCompatibilityTracker" argument of an
2971514c033dSJohannes Doerfert       // __kmpc_target_init or
2972514c033dSJohannes Doerfert       // __kmpc_target_deinit call. We will answer this one with the internal
2973514c033dSJohannes Doerfert       // state.
297497387fdfSJohannes Doerfert       if (!SPMDCompatibilityTracker.isValidState())
2975514c033dSJohannes Doerfert         return nullptr;
2976514c033dSJohannes Doerfert       if (!SPMDCompatibilityTracker.isAtFixpoint()) {
2977514c033dSJohannes Doerfert         if (AA)
2978514c033dSJohannes Doerfert           A.recordDependence(*this, *AA, DepClassTy::OPTIONAL);
2979514c033dSJohannes Doerfert         UsedAssumedInformation = true;
2980514c033dSJohannes Doerfert       } else {
2981514c033dSJohannes Doerfert         UsedAssumedInformation = false;
2982514c033dSJohannes Doerfert       }
2983423d34f7SShilei Tian       auto *Val = ConstantInt::getSigned(
2984423d34f7SShilei Tian           IntegerType::getInt8Ty(IRP.getAnchorValue().getContext()),
2985423d34f7SShilei Tian           SPMDCompatibilityTracker.isAssumed() ? OMP_TGT_EXEC_MODE_SPMD
2986423d34f7SShilei Tian                                                : OMP_TGT_EXEC_MODE_GENERIC);
2987514c033dSJohannes Doerfert       return Val;
2988514c033dSJohannes Doerfert     };
2989514c033dSJohannes Doerfert 
2990e8439ec8SGiorgis Georgakoudis     Attributor::SimplifictionCallbackTy IsGenericModeSimplifyCB =
2991e8439ec8SGiorgis Georgakoudis         [&](const IRPosition &IRP, const AbstractAttribute *AA,
2992e8439ec8SGiorgis Georgakoudis             bool &UsedAssumedInformation) -> Optional<Value *> {
2993e8439ec8SGiorgis Georgakoudis       // IRP represents the "RequiresFullRuntime" argument of an
2994e8439ec8SGiorgis Georgakoudis       // __kmpc_target_init or __kmpc_target_deinit call. We will answer this
2995e8439ec8SGiorgis Georgakoudis       // one with the internal state of the SPMDCompatibilityTracker, so if
2996e8439ec8SGiorgis Georgakoudis       // generic then true, if SPMD then false.
2997e8439ec8SGiorgis Georgakoudis       if (!SPMDCompatibilityTracker.isValidState())
2998e8439ec8SGiorgis Georgakoudis         return nullptr;
2999e8439ec8SGiorgis Georgakoudis       if (!SPMDCompatibilityTracker.isAtFixpoint()) {
3000e8439ec8SGiorgis Georgakoudis         if (AA)
3001e8439ec8SGiorgis Georgakoudis           A.recordDependence(*this, *AA, DepClassTy::OPTIONAL);
3002e8439ec8SGiorgis Georgakoudis         UsedAssumedInformation = true;
3003e8439ec8SGiorgis Georgakoudis       } else {
3004e8439ec8SGiorgis Georgakoudis         UsedAssumedInformation = false;
3005e8439ec8SGiorgis Georgakoudis       }
3006e8439ec8SGiorgis Georgakoudis       auto *Val = ConstantInt::getBool(IRP.getAnchorValue().getContext(),
3007e8439ec8SGiorgis Georgakoudis                                        !SPMDCompatibilityTracker.isAssumed());
3008e8439ec8SGiorgis Georgakoudis       return Val;
3009e8439ec8SGiorgis Georgakoudis     };
3010e8439ec8SGiorgis Georgakoudis 
3011423d34f7SShilei Tian     constexpr const int InitModeArgNo = 1;
3012423d34f7SShilei Tian     constexpr const int DeinitModeArgNo = 1;
3013d9659bf6SJohannes Doerfert     constexpr const int InitUseStateMachineArgNo = 2;
3014e8439ec8SGiorgis Georgakoudis     constexpr const int InitRequiresFullRuntimeArgNo = 3;
3015e8439ec8SGiorgis Georgakoudis     constexpr const int DeinitRequiresFullRuntimeArgNo = 2;
3016d9659bf6SJohannes Doerfert     A.registerSimplificationCallback(
3017d9659bf6SJohannes Doerfert         IRPosition::callsite_argument(*KernelInitCB, InitUseStateMachineArgNo),
3018d9659bf6SJohannes Doerfert         StateMachineSimplifyCB);
3019514c033dSJohannes Doerfert     A.registerSimplificationCallback(
3020423d34f7SShilei Tian         IRPosition::callsite_argument(*KernelInitCB, InitModeArgNo),
3021423d34f7SShilei Tian         ModeSimplifyCB);
3022514c033dSJohannes Doerfert     A.registerSimplificationCallback(
3023423d34f7SShilei Tian         IRPosition::callsite_argument(*KernelDeinitCB, DeinitModeArgNo),
3024423d34f7SShilei Tian         ModeSimplifyCB);
3025e8439ec8SGiorgis Georgakoudis     A.registerSimplificationCallback(
3026e8439ec8SGiorgis Georgakoudis         IRPosition::callsite_argument(*KernelInitCB,
3027e8439ec8SGiorgis Georgakoudis                                       InitRequiresFullRuntimeArgNo),
3028e8439ec8SGiorgis Georgakoudis         IsGenericModeSimplifyCB);
3029e8439ec8SGiorgis Georgakoudis     A.registerSimplificationCallback(
3030e8439ec8SGiorgis Georgakoudis         IRPosition::callsite_argument(*KernelDeinitCB,
3031e8439ec8SGiorgis Georgakoudis                                       DeinitRequiresFullRuntimeArgNo),
3032e8439ec8SGiorgis Georgakoudis         IsGenericModeSimplifyCB);
3033514c033dSJohannes Doerfert 
3034514c033dSJohannes Doerfert     // Check if we know we are in SPMD-mode already.
3035423d34f7SShilei Tian     ConstantInt *ModeArg =
3036423d34f7SShilei Tian         dyn_cast<ConstantInt>(KernelInitCB->getArgOperand(InitModeArgNo));
3037423d34f7SShilei Tian     if (ModeArg && (ModeArg->getSExtValue() & OMP_TGT_EXEC_MODE_SPMD))
3038514c033dSJohannes Doerfert       SPMDCompatibilityTracker.indicateOptimisticFixpoint();
303960e643feSGiorgis Georgakoudis     // This is a generic region but SPMDization is disabled so stop tracking.
304060e643feSGiorgis Georgakoudis     else if (DisableOpenMPOptSPMDization)
304160e643feSGiorgis Georgakoudis       SPMDCompatibilityTracker.indicatePessimisticFixpoint();
3042d9659bf6SJohannes Doerfert   }
3043d9659bf6SJohannes Doerfert 
3044e6e440aeSJohannes Doerfert   /// Sanitize the string \p S such that it is a suitable global symbol name.
3045e6e440aeSJohannes Doerfert   static std::string sanitizeForGlobalName(std::string S) {
3046e6e440aeSJohannes Doerfert     std::replace_if(
3047e6e440aeSJohannes Doerfert         S.begin(), S.end(),
3048e6e440aeSJohannes Doerfert         [](const char C) {
3049e6e440aeSJohannes Doerfert           return !((C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z') ||
3050e6e440aeSJohannes Doerfert                    (C >= '0' && C <= '9') || C == '_');
3051e6e440aeSJohannes Doerfert         },
3052e6e440aeSJohannes Doerfert         '.');
3053e6e440aeSJohannes Doerfert     return S;
3054e6e440aeSJohannes Doerfert   }
3055e6e440aeSJohannes Doerfert 
3056d9659bf6SJohannes Doerfert   /// Modify the IR based on the KernelInfoState as the fixpoint iteration is
3057d9659bf6SJohannes Doerfert   /// finished now.
3058d9659bf6SJohannes Doerfert   ChangeStatus manifest(Attributor &A) override {
3059d9659bf6SJohannes Doerfert     // If we are not looking at a kernel with __kmpc_target_init and
3060d9659bf6SJohannes Doerfert     // __kmpc_target_deinit call we cannot actually manifest the information.
3061d9659bf6SJohannes Doerfert     if (!KernelInitCB || !KernelDeinitCB)
3062d9659bf6SJohannes Doerfert       return ChangeStatus::UNCHANGED;
3063d9659bf6SJohannes Doerfert 
3064514c033dSJohannes Doerfert     // If we can we change the execution mode to SPMD-mode otherwise we build a
3065514c033dSJohannes Doerfert     // custom state machine.
3066d61aac76SJohannes Doerfert     ChangeStatus Changed = ChangeStatus::UNCHANGED;
3067d61aac76SJohannes Doerfert     if (!changeToSPMDMode(A, Changed))
3068c6457dcaSJohannes Doerfert       return buildCustomStateMachine(A);
3069d9659bf6SJohannes Doerfert 
3070d61aac76SJohannes Doerfert     return Changed;
3071d9659bf6SJohannes Doerfert   }
3072d9659bf6SJohannes Doerfert 
3073d61aac76SJohannes Doerfert   bool changeToSPMDMode(Attributor &A, ChangeStatus &Changed) {
3074eef6601bSJoseph Huber     auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
3075eef6601bSJoseph Huber 
3076514c033dSJohannes Doerfert     if (!SPMDCompatibilityTracker.isAssumed()) {
3077514c033dSJohannes Doerfert       for (Instruction *NonCompatibleI : SPMDCompatibilityTracker) {
3078514c033dSJohannes Doerfert         if (!NonCompatibleI)
3079514c033dSJohannes Doerfert           continue;
3080eef6601bSJoseph Huber 
3081eef6601bSJoseph Huber         // Skip diagnostics on calls to known OpenMP runtime functions for now.
3082eef6601bSJoseph Huber         if (auto *CB = dyn_cast<CallBase>(NonCompatibleI))
3083eef6601bSJoseph Huber           if (OMPInfoCache.RTLFunctions.contains(CB->getCalledFunction()))
3084eef6601bSJoseph Huber             continue;
3085eef6601bSJoseph Huber 
3086514c033dSJohannes Doerfert         auto Remark = [&](OptimizationRemarkAnalysis ORA) {
3087eef6601bSJoseph Huber           ORA << "Value has potential side effects preventing SPMD-mode "
3088eef6601bSJoseph Huber                  "execution";
3089eef6601bSJoseph Huber           if (isa<CallBase>(NonCompatibleI)) {
3090eef6601bSJoseph Huber             ORA << ". Add `__attribute__((assume(\"ompx_spmd_amenable\")))` to "
3091eef6601bSJoseph Huber                    "the called function to override";
3092514c033dSJohannes Doerfert           }
3093514c033dSJohannes Doerfert           return ORA << ".";
3094514c033dSJohannes Doerfert         };
30952c31d5ebSJoseph Huber         A.emitRemark<OptimizationRemarkAnalysis>(NonCompatibleI, "OMP121",
30962c31d5ebSJoseph Huber                                                  Remark);
3097514c033dSJohannes Doerfert 
3098514c033dSJohannes Doerfert         LLVM_DEBUG(dbgs() << TAG << "SPMD-incompatible side-effect: "
3099514c033dSJohannes Doerfert                           << *NonCompatibleI << "\n");
3100514c033dSJohannes Doerfert       }
3101514c033dSJohannes Doerfert 
3102514c033dSJohannes Doerfert       return false;
3103514c033dSJohannes Doerfert     }
3104514c033dSJohannes Doerfert 
3105d61aac76SJohannes Doerfert     // Check if the kernel is already in SPMD mode, if so, return success.
3106d61aac76SJohannes Doerfert     Function *Kernel = getAnchorScope();
3107d61aac76SJohannes Doerfert     GlobalVariable *ExecMode = Kernel->getParent()->getGlobalVariable(
3108d61aac76SJohannes Doerfert         (Kernel->getName() + "_exec_mode").str());
3109d61aac76SJohannes Doerfert     assert(ExecMode && "Kernel without exec mode?");
3110d61aac76SJohannes Doerfert     assert(ExecMode->getInitializer() && "ExecMode doesn't have initializer!");
3111d61aac76SJohannes Doerfert 
3112d61aac76SJohannes Doerfert     // Set the global exec mode flag to indicate SPMD-Generic mode.
3113d61aac76SJohannes Doerfert     assert(isa<ConstantInt>(ExecMode->getInitializer()) &&
3114d61aac76SJohannes Doerfert            "ExecMode is not an integer!");
3115d61aac76SJohannes Doerfert     const int8_t ExecModeVal =
3116d61aac76SJohannes Doerfert         cast<ConstantInt>(ExecMode->getInitializer())->getSExtValue();
3117d61aac76SJohannes Doerfert     if (ExecModeVal != OMP_TGT_EXEC_MODE_GENERIC)
3118d61aac76SJohannes Doerfert       return true;
3119d61aac76SJohannes Doerfert 
3120d61aac76SJohannes Doerfert     // We will now unconditionally modify the IR, indicate a change.
3121d61aac76SJohannes Doerfert     Changed = ChangeStatus::CHANGED;
3122d61aac76SJohannes Doerfert 
312329a3e3ddSGiorgis Georgakoudis     auto CreateGuardedRegion = [&](Instruction *RegionStartI,
312429a3e3ddSGiorgis Georgakoudis                                    Instruction *RegionEndI) {
312529a3e3ddSGiorgis Georgakoudis       LoopInfo *LI = nullptr;
312629a3e3ddSGiorgis Georgakoudis       DominatorTree *DT = nullptr;
312729a3e3ddSGiorgis Georgakoudis       MemorySSAUpdater *MSU = nullptr;
312829a3e3ddSGiorgis Georgakoudis       using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
312929a3e3ddSGiorgis Georgakoudis 
313029a3e3ddSGiorgis Georgakoudis       BasicBlock *ParentBB = RegionStartI->getParent();
313129a3e3ddSGiorgis Georgakoudis       Function *Fn = ParentBB->getParent();
313229a3e3ddSGiorgis Georgakoudis       Module &M = *Fn->getParent();
313329a3e3ddSGiorgis Georgakoudis 
313429a3e3ddSGiorgis Georgakoudis       // Create all the blocks and logic.
313529a3e3ddSGiorgis Georgakoudis       // ParentBB:
313629a3e3ddSGiorgis Georgakoudis       //    goto RegionCheckTidBB
313729a3e3ddSGiorgis Georgakoudis       // RegionCheckTidBB:
313829a3e3ddSGiorgis Georgakoudis       //    Tid = __kmpc_hardware_thread_id()
313929a3e3ddSGiorgis Georgakoudis       //    if (Tid != 0)
314029a3e3ddSGiorgis Georgakoudis       //        goto RegionBarrierBB
314129a3e3ddSGiorgis Georgakoudis       // RegionStartBB:
314229a3e3ddSGiorgis Georgakoudis       //    <execute instructions guarded>
314329a3e3ddSGiorgis Georgakoudis       //    goto RegionEndBB
314429a3e3ddSGiorgis Georgakoudis       // RegionEndBB:
314529a3e3ddSGiorgis Georgakoudis       //    <store escaping values to shared mem>
314629a3e3ddSGiorgis Georgakoudis       //    goto RegionBarrierBB
314729a3e3ddSGiorgis Georgakoudis       //  RegionBarrierBB:
314829a3e3ddSGiorgis Georgakoudis       //    __kmpc_simple_barrier_spmd()
314929a3e3ddSGiorgis Georgakoudis       //    // second barrier is omitted if lacking escaping values.
315029a3e3ddSGiorgis Georgakoudis       //    <load escaping values from shared mem>
315129a3e3ddSGiorgis Georgakoudis       //    __kmpc_simple_barrier_spmd()
315229a3e3ddSGiorgis Georgakoudis       //    goto RegionExitBB
315329a3e3ddSGiorgis Georgakoudis       // RegionExitBB:
315429a3e3ddSGiorgis Georgakoudis       //    <execute rest of instructions>
315529a3e3ddSGiorgis Georgakoudis 
315629a3e3ddSGiorgis Georgakoudis       BasicBlock *RegionEndBB = SplitBlock(ParentBB, RegionEndI->getNextNode(),
315729a3e3ddSGiorgis Georgakoudis                                            DT, LI, MSU, "region.guarded.end");
315829a3e3ddSGiorgis Georgakoudis       BasicBlock *RegionBarrierBB =
315929a3e3ddSGiorgis Georgakoudis           SplitBlock(RegionEndBB, &*RegionEndBB->getFirstInsertionPt(), DT, LI,
316029a3e3ddSGiorgis Georgakoudis                      MSU, "region.barrier");
316129a3e3ddSGiorgis Georgakoudis       BasicBlock *RegionExitBB =
316229a3e3ddSGiorgis Georgakoudis           SplitBlock(RegionBarrierBB, &*RegionBarrierBB->getFirstInsertionPt(),
316329a3e3ddSGiorgis Georgakoudis                      DT, LI, MSU, "region.exit");
316429a3e3ddSGiorgis Georgakoudis       BasicBlock *RegionStartBB =
316529a3e3ddSGiorgis Georgakoudis           SplitBlock(ParentBB, RegionStartI, DT, LI, MSU, "region.guarded");
316629a3e3ddSGiorgis Georgakoudis 
316729a3e3ddSGiorgis Georgakoudis       assert(ParentBB->getUniqueSuccessor() == RegionStartBB &&
316829a3e3ddSGiorgis Georgakoudis              "Expected a different CFG");
316929a3e3ddSGiorgis Georgakoudis 
317029a3e3ddSGiorgis Georgakoudis       BasicBlock *RegionCheckTidBB = SplitBlock(
317129a3e3ddSGiorgis Georgakoudis           ParentBB, ParentBB->getTerminator(), DT, LI, MSU, "region.check.tid");
317229a3e3ddSGiorgis Georgakoudis 
317329a3e3ddSGiorgis Georgakoudis       // Register basic blocks with the Attributor.
317429a3e3ddSGiorgis Georgakoudis       A.registerManifestAddedBasicBlock(*RegionEndBB);
317529a3e3ddSGiorgis Georgakoudis       A.registerManifestAddedBasicBlock(*RegionBarrierBB);
317629a3e3ddSGiorgis Georgakoudis       A.registerManifestAddedBasicBlock(*RegionExitBB);
317729a3e3ddSGiorgis Georgakoudis       A.registerManifestAddedBasicBlock(*RegionStartBB);
317829a3e3ddSGiorgis Georgakoudis       A.registerManifestAddedBasicBlock(*RegionCheckTidBB);
317929a3e3ddSGiorgis Georgakoudis 
318029a3e3ddSGiorgis Georgakoudis       bool HasBroadcastValues = false;
318129a3e3ddSGiorgis Georgakoudis       // Find escaping outputs from the guarded region to outside users and
318229a3e3ddSGiorgis Georgakoudis       // broadcast their values to them.
318329a3e3ddSGiorgis Georgakoudis       for (Instruction &I : *RegionStartBB) {
318429a3e3ddSGiorgis Georgakoudis         SmallPtrSet<Instruction *, 4> OutsideUsers;
318529a3e3ddSGiorgis Georgakoudis         for (User *Usr : I.users()) {
318629a3e3ddSGiorgis Georgakoudis           Instruction &UsrI = *cast<Instruction>(Usr);
318729a3e3ddSGiorgis Georgakoudis           if (UsrI.getParent() != RegionStartBB)
318829a3e3ddSGiorgis Georgakoudis             OutsideUsers.insert(&UsrI);
318929a3e3ddSGiorgis Georgakoudis         }
319029a3e3ddSGiorgis Georgakoudis 
319129a3e3ddSGiorgis Georgakoudis         if (OutsideUsers.empty())
319229a3e3ddSGiorgis Georgakoudis           continue;
319329a3e3ddSGiorgis Georgakoudis 
319429a3e3ddSGiorgis Georgakoudis         HasBroadcastValues = true;
319529a3e3ddSGiorgis Georgakoudis 
319629a3e3ddSGiorgis Georgakoudis         // Emit a global variable in shared memory to store the broadcasted
319729a3e3ddSGiorgis Georgakoudis         // value.
319829a3e3ddSGiorgis Georgakoudis         auto *SharedMem = new GlobalVariable(
319929a3e3ddSGiorgis Georgakoudis             M, I.getType(), /* IsConstant */ false,
320029a3e3ddSGiorgis Georgakoudis             GlobalValue::InternalLinkage, UndefValue::get(I.getType()),
3201e6e440aeSJohannes Doerfert             sanitizeForGlobalName(
3202e6e440aeSJohannes Doerfert                 (I.getName() + ".guarded.output.alloc").str()),
3203e6e440aeSJohannes Doerfert             nullptr, GlobalValue::NotThreadLocal,
320429a3e3ddSGiorgis Georgakoudis             static_cast<unsigned>(AddressSpace::Shared));
320529a3e3ddSGiorgis Georgakoudis 
320629a3e3ddSGiorgis Georgakoudis         // Emit a store instruction to update the value.
320729a3e3ddSGiorgis Georgakoudis         new StoreInst(&I, SharedMem, RegionEndBB->getTerminator());
320829a3e3ddSGiorgis Georgakoudis 
320929a3e3ddSGiorgis Georgakoudis         LoadInst *LoadI = new LoadInst(I.getType(), SharedMem,
321029a3e3ddSGiorgis Georgakoudis                                        I.getName() + ".guarded.output.load",
321129a3e3ddSGiorgis Georgakoudis                                        RegionBarrierBB->getTerminator());
321229a3e3ddSGiorgis Georgakoudis 
321329a3e3ddSGiorgis Georgakoudis         // Emit a load instruction and replace uses of the output value.
3214e6e440aeSJohannes Doerfert         for (Instruction *UsrI : OutsideUsers)
321529a3e3ddSGiorgis Georgakoudis           UsrI->replaceUsesOfWith(&I, LoadI);
321629a3e3ddSGiorgis Georgakoudis       }
321729a3e3ddSGiorgis Georgakoudis 
321829a3e3ddSGiorgis Georgakoudis       auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
321929a3e3ddSGiorgis Georgakoudis 
322029a3e3ddSGiorgis Georgakoudis       // Go to tid check BB in ParentBB.
322129a3e3ddSGiorgis Georgakoudis       const DebugLoc DL = ParentBB->getTerminator()->getDebugLoc();
322229a3e3ddSGiorgis Georgakoudis       ParentBB->getTerminator()->eraseFromParent();
322329a3e3ddSGiorgis Georgakoudis       OpenMPIRBuilder::LocationDescription Loc(
322429a3e3ddSGiorgis Georgakoudis           InsertPointTy(ParentBB, ParentBB->end()), DL);
322529a3e3ddSGiorgis Georgakoudis       OMPInfoCache.OMPBuilder.updateToLocation(Loc);
3226944aa042SJohannes Doerfert       uint32_t SrcLocStrSize;
3227944aa042SJohannes Doerfert       auto *SrcLocStr =
3228944aa042SJohannes Doerfert           OMPInfoCache.OMPBuilder.getOrCreateSrcLocStr(Loc, SrcLocStrSize);
3229944aa042SJohannes Doerfert       Value *Ident =
3230944aa042SJohannes Doerfert           OMPInfoCache.OMPBuilder.getOrCreateIdent(SrcLocStr, SrcLocStrSize);
323129a3e3ddSGiorgis Georgakoudis       BranchInst::Create(RegionCheckTidBB, ParentBB)->setDebugLoc(DL);
323229a3e3ddSGiorgis Georgakoudis 
323329a3e3ddSGiorgis Georgakoudis       // Add check for Tid in RegionCheckTidBB
323429a3e3ddSGiorgis Georgakoudis       RegionCheckTidBB->getTerminator()->eraseFromParent();
323529a3e3ddSGiorgis Georgakoudis       OpenMPIRBuilder::LocationDescription LocRegionCheckTid(
323629a3e3ddSGiorgis Georgakoudis           InsertPointTy(RegionCheckTidBB, RegionCheckTidBB->end()), DL);
323729a3e3ddSGiorgis Georgakoudis       OMPInfoCache.OMPBuilder.updateToLocation(LocRegionCheckTid);
323829a3e3ddSGiorgis Georgakoudis       FunctionCallee HardwareTidFn =
323929a3e3ddSGiorgis Georgakoudis           OMPInfoCache.OMPBuilder.getOrCreateRuntimeFunction(
324029a3e3ddSGiorgis Georgakoudis               M, OMPRTL___kmpc_get_hardware_thread_id_in_block);
324129a3e3ddSGiorgis Georgakoudis       Value *Tid =
324229a3e3ddSGiorgis Georgakoudis           OMPInfoCache.OMPBuilder.Builder.CreateCall(HardwareTidFn, {});
324329a3e3ddSGiorgis Georgakoudis       Value *TidCheck = OMPInfoCache.OMPBuilder.Builder.CreateIsNull(Tid);
324429a3e3ddSGiorgis Georgakoudis       OMPInfoCache.OMPBuilder.Builder
324529a3e3ddSGiorgis Georgakoudis           .CreateCondBr(TidCheck, RegionStartBB, RegionBarrierBB)
324629a3e3ddSGiorgis Georgakoudis           ->setDebugLoc(DL);
324729a3e3ddSGiorgis Georgakoudis 
324829a3e3ddSGiorgis Georgakoudis       // First barrier for synchronization, ensures main thread has updated
324929a3e3ddSGiorgis Georgakoudis       // values.
325029a3e3ddSGiorgis Georgakoudis       FunctionCallee BarrierFn =
325129a3e3ddSGiorgis Georgakoudis           OMPInfoCache.OMPBuilder.getOrCreateRuntimeFunction(
325229a3e3ddSGiorgis Georgakoudis               M, OMPRTL___kmpc_barrier_simple_spmd);
325329a3e3ddSGiorgis Georgakoudis       OMPInfoCache.OMPBuilder.updateToLocation(InsertPointTy(
325429a3e3ddSGiorgis Georgakoudis           RegionBarrierBB, RegionBarrierBB->getFirstInsertionPt()));
325529a3e3ddSGiorgis Georgakoudis       OMPInfoCache.OMPBuilder.Builder.CreateCall(BarrierFn, {Ident, Tid})
325629a3e3ddSGiorgis Georgakoudis           ->setDebugLoc(DL);
325729a3e3ddSGiorgis Georgakoudis 
325829a3e3ddSGiorgis Georgakoudis       // Second barrier ensures workers have read broadcast values.
325929a3e3ddSGiorgis Georgakoudis       if (HasBroadcastValues)
326029a3e3ddSGiorgis Georgakoudis         CallInst::Create(BarrierFn, {Ident, Tid}, "",
326129a3e3ddSGiorgis Georgakoudis                          RegionBarrierBB->getTerminator())
326229a3e3ddSGiorgis Georgakoudis             ->setDebugLoc(DL);
326329a3e3ddSGiorgis Georgakoudis     };
326429a3e3ddSGiorgis Georgakoudis 
326599ea8ac9SJohannes Doerfert     auto &AllocSharedRFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
326699ea8ac9SJohannes Doerfert     SmallPtrSet<BasicBlock *, 8> Visited;
326799ea8ac9SJohannes Doerfert     for (Instruction *GuardedI : SPMDCompatibilityTracker) {
326899ea8ac9SJohannes Doerfert       BasicBlock *BB = GuardedI->getParent();
326999ea8ac9SJohannes Doerfert       if (!Visited.insert(BB).second)
327099ea8ac9SJohannes Doerfert         continue;
327199ea8ac9SJohannes Doerfert 
327299ea8ac9SJohannes Doerfert       SmallVector<std::pair<Instruction *, Instruction *>> Reorders;
327399ea8ac9SJohannes Doerfert       Instruction *LastEffect = nullptr;
327499ea8ac9SJohannes Doerfert       BasicBlock::reverse_iterator IP = BB->rbegin(), IPEnd = BB->rend();
327599ea8ac9SJohannes Doerfert       while (++IP != IPEnd) {
327699ea8ac9SJohannes Doerfert         if (!IP->mayHaveSideEffects() && !IP->mayReadFromMemory())
327799ea8ac9SJohannes Doerfert           continue;
327899ea8ac9SJohannes Doerfert         Instruction *I = &*IP;
327999ea8ac9SJohannes Doerfert         if (OpenMPOpt::getCallIfRegularCall(*I, &AllocSharedRFI))
328099ea8ac9SJohannes Doerfert           continue;
328199ea8ac9SJohannes Doerfert         if (!I->user_empty() || !SPMDCompatibilityTracker.contains(I)) {
328299ea8ac9SJohannes Doerfert           LastEffect = nullptr;
328399ea8ac9SJohannes Doerfert           continue;
328499ea8ac9SJohannes Doerfert         }
328599ea8ac9SJohannes Doerfert         if (LastEffect)
328699ea8ac9SJohannes Doerfert           Reorders.push_back({I, LastEffect});
328799ea8ac9SJohannes Doerfert         LastEffect = &*IP;
328899ea8ac9SJohannes Doerfert       }
328999ea8ac9SJohannes Doerfert       for (auto &Reorder : Reorders)
329099ea8ac9SJohannes Doerfert         Reorder.first->moveBefore(Reorder.second);
329199ea8ac9SJohannes Doerfert     }
329299ea8ac9SJohannes Doerfert 
329329a3e3ddSGiorgis Georgakoudis     SmallVector<std::pair<Instruction *, Instruction *>, 4> GuardedRegions;
329429a3e3ddSGiorgis Georgakoudis 
329529a3e3ddSGiorgis Georgakoudis     for (Instruction *GuardedI : SPMDCompatibilityTracker) {
329629a3e3ddSGiorgis Georgakoudis       BasicBlock *BB = GuardedI->getParent();
329729a3e3ddSGiorgis Georgakoudis       auto *CalleeAA = A.lookupAAFor<AAKernelInfo>(
329829a3e3ddSGiorgis Georgakoudis           IRPosition::function(*GuardedI->getFunction()), nullptr,
329929a3e3ddSGiorgis Georgakoudis           DepClassTy::NONE);
330029a3e3ddSGiorgis Georgakoudis       assert(CalleeAA != nullptr && "Expected Callee AAKernelInfo");
330129a3e3ddSGiorgis Georgakoudis       auto &CalleeAAFunction = *cast<AAKernelInfoFunction>(CalleeAA);
330229a3e3ddSGiorgis Georgakoudis       // Continue if instruction is already guarded.
330329a3e3ddSGiorgis Georgakoudis       if (CalleeAAFunction.getGuardedInstructions().contains(GuardedI))
330429a3e3ddSGiorgis Georgakoudis         continue;
330529a3e3ddSGiorgis Georgakoudis 
330629a3e3ddSGiorgis Georgakoudis       Instruction *GuardedRegionStart = nullptr, *GuardedRegionEnd = nullptr;
330729a3e3ddSGiorgis Georgakoudis       for (Instruction &I : *BB) {
330829a3e3ddSGiorgis Georgakoudis         // If instruction I needs to be guarded update the guarded region
330929a3e3ddSGiorgis Georgakoudis         // bounds.
331029a3e3ddSGiorgis Georgakoudis         if (SPMDCompatibilityTracker.contains(&I)) {
331129a3e3ddSGiorgis Georgakoudis           CalleeAAFunction.getGuardedInstructions().insert(&I);
331229a3e3ddSGiorgis Georgakoudis           if (GuardedRegionStart)
331329a3e3ddSGiorgis Georgakoudis             GuardedRegionEnd = &I;
331429a3e3ddSGiorgis Georgakoudis           else
331529a3e3ddSGiorgis Georgakoudis             GuardedRegionStart = GuardedRegionEnd = &I;
331629a3e3ddSGiorgis Georgakoudis 
331729a3e3ddSGiorgis Georgakoudis           continue;
331829a3e3ddSGiorgis Georgakoudis         }
331929a3e3ddSGiorgis Georgakoudis 
332029a3e3ddSGiorgis Georgakoudis         // Instruction I does not need guarding, store
332129a3e3ddSGiorgis Georgakoudis         // any region found and reset bounds.
332229a3e3ddSGiorgis Georgakoudis         if (GuardedRegionStart) {
332329a3e3ddSGiorgis Georgakoudis           GuardedRegions.push_back(
332429a3e3ddSGiorgis Georgakoudis               std::make_pair(GuardedRegionStart, GuardedRegionEnd));
332529a3e3ddSGiorgis Georgakoudis           GuardedRegionStart = nullptr;
332629a3e3ddSGiorgis Georgakoudis           GuardedRegionEnd = nullptr;
332729a3e3ddSGiorgis Georgakoudis         }
332829a3e3ddSGiorgis Georgakoudis       }
332929a3e3ddSGiorgis Georgakoudis     }
333029a3e3ddSGiorgis Georgakoudis 
333129a3e3ddSGiorgis Georgakoudis     for (auto &GR : GuardedRegions)
333229a3e3ddSGiorgis Georgakoudis       CreateGuardedRegion(GR.first, GR.second);
333329a3e3ddSGiorgis Georgakoudis 
3334514c033dSJohannes Doerfert     // Adjust the global exec mode flag that tells the runtime what mode this
3335514c033dSJohannes Doerfert     // kernel is executed in.
3336ca999f71SShilei Tian     assert(ExecModeVal == OMP_TGT_EXEC_MODE_GENERIC &&
3337ca999f71SShilei Tian            "Initially non-SPMD kernel has SPMD exec mode!");
3338514c033dSJohannes Doerfert     ExecMode->setInitializer(
3339ca999f71SShilei Tian         ConstantInt::get(ExecMode->getInitializer()->getType(),
3340ca999f71SShilei Tian                          ExecModeVal | OMP_TGT_EXEC_MODE_GENERIC_SPMD));
3341514c033dSJohannes Doerfert 
3342514c033dSJohannes Doerfert     // Next rewrite the init and deinit calls to indicate we use SPMD-mode now.
3343423d34f7SShilei Tian     const int InitModeArgNo = 1;
3344423d34f7SShilei Tian     const int DeinitModeArgNo = 1;
3345514c033dSJohannes Doerfert     const int InitUseStateMachineArgNo = 2;
3346e8439ec8SGiorgis Georgakoudis     const int InitRequiresFullRuntimeArgNo = 3;
3347e8439ec8SGiorgis Georgakoudis     const int DeinitRequiresFullRuntimeArgNo = 2;
3348514c033dSJohannes Doerfert 
3349514c033dSJohannes Doerfert     auto &Ctx = getAnchorValue().getContext();
3350423d34f7SShilei Tian     A.changeUseAfterManifest(
3351423d34f7SShilei Tian         KernelInitCB->getArgOperandUse(InitModeArgNo),
3352423d34f7SShilei Tian         *ConstantInt::getSigned(IntegerType::getInt8Ty(Ctx),
3353423d34f7SShilei Tian                                 OMP_TGT_EXEC_MODE_SPMD));
3354514c033dSJohannes Doerfert     A.changeUseAfterManifest(
3355514c033dSJohannes Doerfert         KernelInitCB->getArgOperandUse(InitUseStateMachineArgNo),
33562aed0813SKazu Hirata         *ConstantInt::getBool(Ctx, false));
3357514c033dSJohannes Doerfert     A.changeUseAfterManifest(
3358423d34f7SShilei Tian         KernelDeinitCB->getArgOperandUse(DeinitModeArgNo),
3359423d34f7SShilei Tian         *ConstantInt::getSigned(IntegerType::getInt8Ty(Ctx),
3360423d34f7SShilei Tian                                 OMP_TGT_EXEC_MODE_SPMD));
3361e8439ec8SGiorgis Georgakoudis     A.changeUseAfterManifest(
3362e8439ec8SGiorgis Georgakoudis         KernelInitCB->getArgOperandUse(InitRequiresFullRuntimeArgNo),
33632aed0813SKazu Hirata         *ConstantInt::getBool(Ctx, false));
3364e8439ec8SGiorgis Georgakoudis     A.changeUseAfterManifest(
3365e8439ec8SGiorgis Georgakoudis         KernelDeinitCB->getArgOperandUse(DeinitRequiresFullRuntimeArgNo),
33662aed0813SKazu Hirata         *ConstantInt::getBool(Ctx, false));
3367e8439ec8SGiorgis Georgakoudis 
3368514c033dSJohannes Doerfert     ++NumOpenMPTargetRegionKernelsSPMD;
3369514c033dSJohannes Doerfert 
3370514c033dSJohannes Doerfert     auto Remark = [&](OptimizationRemark OR) {
3371eef6601bSJoseph Huber       return OR << "Transformed generic-mode kernel to SPMD-mode.";
3372514c033dSJohannes Doerfert     };
33732c31d5ebSJoseph Huber     A.emitRemark<OptimizationRemark>(KernelInitCB, "OMP120", Remark);
3374514c033dSJohannes Doerfert     return true;
3375514c033dSJohannes Doerfert   };
3376514c033dSJohannes Doerfert 
3377d9659bf6SJohannes Doerfert   ChangeStatus buildCustomStateMachine(Attributor &A) {
3378cd0dd8ecSJoseph Huber     // If we have disabled state machine rewrites, don't make a custom one
3379cd0dd8ecSJoseph Huber     if (DisableOpenMPOptStateMachineRewrite)
3380c6457dcaSJohannes Doerfert       return ChangeStatus::UNCHANGED;
3381cd0dd8ecSJoseph Huber 
3382f074a6a0SJoseph Huber     // Don't rewrite the state machine if we are not in a valid state.
3383f074a6a0SJoseph Huber     if (!ReachedKnownParallelRegions.isValidState())
3384f074a6a0SJoseph Huber       return ChangeStatus::UNCHANGED;
3385d9659bf6SJohannes Doerfert 
3386423d34f7SShilei Tian     const int InitModeArgNo = 1;
3387d9659bf6SJohannes Doerfert     const int InitUseStateMachineArgNo = 2;
3388d9659bf6SJohannes Doerfert 
3389d9659bf6SJohannes Doerfert     // Check if the current configuration is non-SPMD and generic state machine.
3390d9659bf6SJohannes Doerfert     // If we already have SPMD mode or a custom state machine we do not need to
3391d9659bf6SJohannes Doerfert     // go any further. If it is anything but a constant something is weird and
3392d9659bf6SJohannes Doerfert     // we give up.
3393d9659bf6SJohannes Doerfert     ConstantInt *UseStateMachine = dyn_cast<ConstantInt>(
3394d9659bf6SJohannes Doerfert         KernelInitCB->getArgOperand(InitUseStateMachineArgNo));
3395423d34f7SShilei Tian     ConstantInt *Mode =
3396423d34f7SShilei Tian         dyn_cast<ConstantInt>(KernelInitCB->getArgOperand(InitModeArgNo));
3397d9659bf6SJohannes Doerfert 
3398d9659bf6SJohannes Doerfert     // If we are stuck with generic mode, try to create a custom device (=GPU)
3399d9659bf6SJohannes Doerfert     // state machine which is specialized for the parallel regions that are
3400d9659bf6SJohannes Doerfert     // reachable by the kernel.
3401423d34f7SShilei Tian     if (!UseStateMachine || UseStateMachine->isZero() || !Mode ||
3402423d34f7SShilei Tian         (Mode->getSExtValue() & OMP_TGT_EXEC_MODE_SPMD))
3403d9659bf6SJohannes Doerfert       return ChangeStatus::UNCHANGED;
3404d9659bf6SJohannes Doerfert 
3405514c033dSJohannes Doerfert     // If not SPMD mode, indicate we use a custom state machine now.
3406d9659bf6SJohannes Doerfert     auto &Ctx = getAnchorValue().getContext();
34072aed0813SKazu Hirata     auto *FalseVal = ConstantInt::getBool(Ctx, false);
3408d9659bf6SJohannes Doerfert     A.changeUseAfterManifest(
3409d9659bf6SJohannes Doerfert         KernelInitCB->getArgOperandUse(InitUseStateMachineArgNo), *FalseVal);
3410d9659bf6SJohannes Doerfert 
3411d9659bf6SJohannes Doerfert     // If we don't actually need a state machine we are done here. This can
3412d9659bf6SJohannes Doerfert     // happen if there simply are no parallel regions. In the resulting kernel
3413d9659bf6SJohannes Doerfert     // all worker threads will simply exit right away, leaving the main thread
3414d9659bf6SJohannes Doerfert     // to do the work alone.
34156b9a3ec3SJoseph Huber     if (!mayContainParallelRegion()) {
3416d9659bf6SJohannes Doerfert       ++NumOpenMPTargetRegionKernelsWithoutStateMachine;
3417d9659bf6SJohannes Doerfert 
3418d9659bf6SJohannes Doerfert       auto Remark = [&](OptimizationRemark OR) {
3419eef6601bSJoseph Huber         return OR << "Removing unused state machine from generic-mode kernel.";
3420d9659bf6SJohannes Doerfert       };
34212c31d5ebSJoseph Huber       A.emitRemark<OptimizationRemark>(KernelInitCB, "OMP130", Remark);
3422d9659bf6SJohannes Doerfert 
3423d9659bf6SJohannes Doerfert       return ChangeStatus::CHANGED;
3424d9659bf6SJohannes Doerfert     }
3425d9659bf6SJohannes Doerfert 
3426d9659bf6SJohannes Doerfert     // Keep track in the statistics of our new shiny custom state machine.
3427d9659bf6SJohannes Doerfert     if (ReachedUnknownParallelRegions.empty()) {
3428d9659bf6SJohannes Doerfert       ++NumOpenMPTargetRegionKernelsCustomStateMachineWithoutFallback;
3429d9659bf6SJohannes Doerfert 
3430d9659bf6SJohannes Doerfert       auto Remark = [&](OptimizationRemark OR) {
3431eef6601bSJoseph Huber         return OR << "Rewriting generic-mode kernel with a customized state "
3432eef6601bSJoseph Huber                      "machine.";
3433d9659bf6SJohannes Doerfert       };
34342c31d5ebSJoseph Huber       A.emitRemark<OptimizationRemark>(KernelInitCB, "OMP131", Remark);
3435d9659bf6SJohannes Doerfert     } else {
3436d9659bf6SJohannes Doerfert       ++NumOpenMPTargetRegionKernelsCustomStateMachineWithFallback;
3437d9659bf6SJohannes Doerfert 
3438eef6601bSJoseph Huber       auto Remark = [&](OptimizationRemarkAnalysis OR) {
3439d9659bf6SJohannes Doerfert         return OR << "Generic-mode kernel is executed with a customized state "
3440eef6601bSJoseph Huber                      "machine that requires a fallback.";
3441d9659bf6SJohannes Doerfert       };
34422c31d5ebSJoseph Huber       A.emitRemark<OptimizationRemarkAnalysis>(KernelInitCB, "OMP132", Remark);
3443d9659bf6SJohannes Doerfert 
3444d9659bf6SJohannes Doerfert       // Tell the user why we ended up with a fallback.
3445d9659bf6SJohannes Doerfert       for (CallBase *UnknownParallelRegionCB : ReachedUnknownParallelRegions) {
3446d9659bf6SJohannes Doerfert         if (!UnknownParallelRegionCB)
3447d9659bf6SJohannes Doerfert           continue;
3448d9659bf6SJohannes Doerfert         auto Remark = [&](OptimizationRemarkAnalysis ORA) {
3449eef6601bSJoseph Huber           return ORA << "Call may contain unknown parallel regions. Use "
3450eef6601bSJoseph Huber                      << "`__attribute__((assume(\"omp_no_parallelism\")))` to "
3451eef6601bSJoseph Huber                         "override.";
3452d9659bf6SJohannes Doerfert         };
34532c31d5ebSJoseph Huber         A.emitRemark<OptimizationRemarkAnalysis>(UnknownParallelRegionCB,
34542c31d5ebSJoseph Huber                                                  "OMP133", Remark);
3455d9659bf6SJohannes Doerfert       }
3456d9659bf6SJohannes Doerfert     }
3457d9659bf6SJohannes Doerfert 
3458d9659bf6SJohannes Doerfert     // Create all the blocks:
3459d9659bf6SJohannes Doerfert     //
3460d9659bf6SJohannes Doerfert     //                       InitCB = __kmpc_target_init(...)
3461c9dfe322SJoel E. Denny     //                       BlockHwSize =
3462c9dfe322SJoel E. Denny     //                         __kmpc_get_hardware_num_threads_in_block();
3463c9dfe322SJoel E. Denny     //                       WarpSize = __kmpc_get_warp_size();
3464c9dfe322SJoel E. Denny     //                       BlockSize = BlockHwSize - WarpSize;
3465c9dfe322SJoel E. Denny     //                       if (InitCB >= BlockSize) return;
3466c9dfe322SJoel E. Denny     // IsWorkerCheckBB:      bool IsWorker = InitCB >= 0;
3467d9659bf6SJohannes Doerfert     //                       if (IsWorker) {
346873720c80SJohannes Doerfert     // SMBeginBB:               __kmpc_barrier_simple_generic(...);
3469d9659bf6SJohannes Doerfert     //                         void *WorkFn;
3470d9659bf6SJohannes Doerfert     //                         bool Active = __kmpc_kernel_parallel(&WorkFn);
3471d9659bf6SJohannes Doerfert     //                         if (!WorkFn) return;
3472d9659bf6SJohannes Doerfert     // SMIsActiveCheckBB:       if (Active) {
3473d9659bf6SJohannes Doerfert     // SMIfCascadeCurrentBB:      if      (WorkFn == <ParFn0>)
3474d9659bf6SJohannes Doerfert     //                              ParFn0(...);
3475d9659bf6SJohannes Doerfert     // SMIfCascadeCurrentBB:      else if (WorkFn == <ParFn1>)
3476d9659bf6SJohannes Doerfert     //                              ParFn1(...);
3477d9659bf6SJohannes Doerfert     //                            ...
3478d9659bf6SJohannes Doerfert     // SMIfCascadeCurrentBB:      else
3479d9659bf6SJohannes Doerfert     //                              ((WorkFnTy*)WorkFn)(...);
3480d9659bf6SJohannes Doerfert     // SMEndParallelBB:           __kmpc_kernel_end_parallel(...);
3481d9659bf6SJohannes Doerfert     //                          }
348273720c80SJohannes Doerfert     // SMDoneBB:                __kmpc_barrier_simple_generic(...);
3483d9659bf6SJohannes Doerfert     //                          goto SMBeginBB;
3484d9659bf6SJohannes Doerfert     //                       }
3485d9659bf6SJohannes Doerfert     // UserCodeEntryBB:      // user code
3486d9659bf6SJohannes Doerfert     //                       __kmpc_target_deinit(...)
3487d9659bf6SJohannes Doerfert     //
3488d9659bf6SJohannes Doerfert     Function *Kernel = getAssociatedFunction();
3489d9659bf6SJohannes Doerfert     assert(Kernel && "Expected an associated function!");
3490d9659bf6SJohannes Doerfert 
3491d9659bf6SJohannes Doerfert     BasicBlock *InitBB = KernelInitCB->getParent();
3492d9659bf6SJohannes Doerfert     BasicBlock *UserCodeEntryBB = InitBB->splitBasicBlock(
3493d9659bf6SJohannes Doerfert         KernelInitCB->getNextNode(), "thread.user_code.check");
3494c9dfe322SJoel E. Denny     BasicBlock *IsWorkerCheckBB =
3495c9dfe322SJoel E. Denny         BasicBlock::Create(Ctx, "is_worker_check", Kernel, UserCodeEntryBB);
3496d9659bf6SJohannes Doerfert     BasicBlock *StateMachineBeginBB = BasicBlock::Create(
3497d9659bf6SJohannes Doerfert         Ctx, "worker_state_machine.begin", Kernel, UserCodeEntryBB);
3498d9659bf6SJohannes Doerfert     BasicBlock *StateMachineFinishedBB = BasicBlock::Create(
3499d9659bf6SJohannes Doerfert         Ctx, "worker_state_machine.finished", Kernel, UserCodeEntryBB);
3500d9659bf6SJohannes Doerfert     BasicBlock *StateMachineIsActiveCheckBB = BasicBlock::Create(
3501d9659bf6SJohannes Doerfert         Ctx, "worker_state_machine.is_active.check", Kernel, UserCodeEntryBB);
3502d9659bf6SJohannes Doerfert     BasicBlock *StateMachineIfCascadeCurrentBB =
3503d9659bf6SJohannes Doerfert         BasicBlock::Create(Ctx, "worker_state_machine.parallel_region.check",
3504d9659bf6SJohannes Doerfert                            Kernel, UserCodeEntryBB);
3505d9659bf6SJohannes Doerfert     BasicBlock *StateMachineEndParallelBB =
3506d9659bf6SJohannes Doerfert         BasicBlock::Create(Ctx, "worker_state_machine.parallel_region.end",
3507d9659bf6SJohannes Doerfert                            Kernel, UserCodeEntryBB);
3508d9659bf6SJohannes Doerfert     BasicBlock *StateMachineDoneBarrierBB = BasicBlock::Create(
3509d9659bf6SJohannes Doerfert         Ctx, "worker_state_machine.done.barrier", Kernel, UserCodeEntryBB);
35103f71b425SGiorgis Georgakoudis     A.registerManifestAddedBasicBlock(*InitBB);
35113f71b425SGiorgis Georgakoudis     A.registerManifestAddedBasicBlock(*UserCodeEntryBB);
3512c9dfe322SJoel E. Denny     A.registerManifestAddedBasicBlock(*IsWorkerCheckBB);
35133f71b425SGiorgis Georgakoudis     A.registerManifestAddedBasicBlock(*StateMachineBeginBB);
35143f71b425SGiorgis Georgakoudis     A.registerManifestAddedBasicBlock(*StateMachineFinishedBB);
35153f71b425SGiorgis Georgakoudis     A.registerManifestAddedBasicBlock(*StateMachineIsActiveCheckBB);
35163f71b425SGiorgis Georgakoudis     A.registerManifestAddedBasicBlock(*StateMachineIfCascadeCurrentBB);
35173f71b425SGiorgis Georgakoudis     A.registerManifestAddedBasicBlock(*StateMachineEndParallelBB);
35183f71b425SGiorgis Georgakoudis     A.registerManifestAddedBasicBlock(*StateMachineDoneBarrierBB);
3519d9659bf6SJohannes Doerfert 
3520d9659bf6SJohannes Doerfert     const DebugLoc &DLoc = KernelInitCB->getDebugLoc();
3521d9659bf6SJohannes Doerfert     ReturnInst::Create(Ctx, StateMachineFinishedBB)->setDebugLoc(DLoc);
3522d9659bf6SJohannes Doerfert     InitBB->getTerminator()->eraseFromParent();
3523c9dfe322SJoel E. Denny 
3524c9dfe322SJoel E. Denny     Module &M = *Kernel->getParent();
3525c9dfe322SJoel E. Denny     auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
3526c9dfe322SJoel E. Denny     FunctionCallee BlockHwSizeFn =
3527c9dfe322SJoel E. Denny         OMPInfoCache.OMPBuilder.getOrCreateRuntimeFunction(
3528c9dfe322SJoel E. Denny             M, OMPRTL___kmpc_get_hardware_num_threads_in_block);
3529c9dfe322SJoel E. Denny     FunctionCallee WarpSizeFn =
3530c9dfe322SJoel E. Denny         OMPInfoCache.OMPBuilder.getOrCreateRuntimeFunction(
3531c9dfe322SJoel E. Denny             M, OMPRTL___kmpc_get_warp_size);
3532c9dfe322SJoel E. Denny     Instruction *BlockHwSize =
3533c9dfe322SJoel E. Denny         CallInst::Create(BlockHwSizeFn, "block.hw_size", InitBB);
3534c9dfe322SJoel E. Denny     BlockHwSize->setDebugLoc(DLoc);
3535c9dfe322SJoel E. Denny     Instruction *WarpSize = CallInst::Create(WarpSizeFn, "warp.size", InitBB);
3536c9dfe322SJoel E. Denny     WarpSize->setDebugLoc(DLoc);
3537c9dfe322SJoel E. Denny     Instruction *BlockSize =
3538c9dfe322SJoel E. Denny         BinaryOperator::CreateSub(BlockHwSize, WarpSize, "block.size", InitBB);
3539c9dfe322SJoel E. Denny     BlockSize->setDebugLoc(DLoc);
3540c9dfe322SJoel E. Denny     Instruction *IsMainOrWorker =
3541c9dfe322SJoel E. Denny         ICmpInst::Create(ICmpInst::ICmp, llvm::CmpInst::ICMP_SLT, KernelInitCB,
3542c9dfe322SJoel E. Denny                          BlockSize, "thread.is_main_or_worker", InitBB);
3543c9dfe322SJoel E. Denny     IsMainOrWorker->setDebugLoc(DLoc);
3544c9dfe322SJoel E. Denny     BranchInst::Create(IsWorkerCheckBB, StateMachineFinishedBB, IsMainOrWorker,
3545c9dfe322SJoel E. Denny                        InitBB);
3546c9dfe322SJoel E. Denny 
3547d9659bf6SJohannes Doerfert     Instruction *IsWorker =
3548d9659bf6SJohannes Doerfert         ICmpInst::Create(ICmpInst::ICmp, llvm::CmpInst::ICMP_NE, KernelInitCB,
3549d9659bf6SJohannes Doerfert                          ConstantInt::get(KernelInitCB->getType(), -1),
3550c9dfe322SJoel E. Denny                          "thread.is_worker", IsWorkerCheckBB);
3551d9659bf6SJohannes Doerfert     IsWorker->setDebugLoc(DLoc);
3552c9dfe322SJoel E. Denny     BranchInst::Create(StateMachineBeginBB, UserCodeEntryBB, IsWorker,
3553c9dfe322SJoel E. Denny                        IsWorkerCheckBB);
355471052ea1SJon Chesterfield 
3555d9659bf6SJohannes Doerfert     // Create local storage for the work function pointer.
355671052ea1SJon Chesterfield     const DataLayout &DL = M.getDataLayout();
3557d9659bf6SJohannes Doerfert     Type *VoidPtrTy = Type::getInt8PtrTy(Ctx);
355871052ea1SJon Chesterfield     Instruction *WorkFnAI =
355971052ea1SJon Chesterfield         new AllocaInst(VoidPtrTy, DL.getAllocaAddrSpace(), nullptr,
356071052ea1SJon Chesterfield                        "worker.work_fn.addr", &Kernel->getEntryBlock().front());
3561d9659bf6SJohannes Doerfert     WorkFnAI->setDebugLoc(DLoc);
3562d9659bf6SJohannes Doerfert 
3563d9659bf6SJohannes Doerfert     OMPInfoCache.OMPBuilder.updateToLocation(
3564d9659bf6SJohannes Doerfert         OpenMPIRBuilder::LocationDescription(
3565d9659bf6SJohannes Doerfert             IRBuilder<>::InsertPoint(StateMachineBeginBB,
3566d9659bf6SJohannes Doerfert                                      StateMachineBeginBB->end()),
3567d9659bf6SJohannes Doerfert             DLoc));
3568d9659bf6SJohannes Doerfert 
3569d9659bf6SJohannes Doerfert     Value *Ident = KernelInitCB->getArgOperand(0);
3570d9659bf6SJohannes Doerfert     Value *GTid = KernelInitCB;
3571d9659bf6SJohannes Doerfert 
3572d9659bf6SJohannes Doerfert     FunctionCallee BarrierFn =
3573d9659bf6SJohannes Doerfert         OMPInfoCache.OMPBuilder.getOrCreateRuntimeFunction(
357473720c80SJohannes Doerfert             M, OMPRTL___kmpc_barrier_simple_generic);
3575d9659bf6SJohannes Doerfert     CallInst::Create(BarrierFn, {Ident, GTid}, "", StateMachineBeginBB)
3576d9659bf6SJohannes Doerfert         ->setDebugLoc(DLoc);
3577d9659bf6SJohannes Doerfert 
357871052ea1SJon Chesterfield     if (WorkFnAI->getType()->getPointerAddressSpace() !=
357971052ea1SJon Chesterfield         (unsigned int)AddressSpace::Generic) {
358071052ea1SJon Chesterfield       WorkFnAI = new AddrSpaceCastInst(
358171052ea1SJon Chesterfield           WorkFnAI,
358271052ea1SJon Chesterfield           PointerType::getWithSamePointeeType(
358371052ea1SJon Chesterfield               cast<PointerType>(WorkFnAI->getType()),
358471052ea1SJon Chesterfield               (unsigned int)AddressSpace::Generic),
358571052ea1SJon Chesterfield           WorkFnAI->getName() + ".generic", StateMachineBeginBB);
358671052ea1SJon Chesterfield       WorkFnAI->setDebugLoc(DLoc);
358771052ea1SJon Chesterfield     }
358871052ea1SJon Chesterfield 
3589d9659bf6SJohannes Doerfert     FunctionCallee KernelParallelFn =
3590d9659bf6SJohannes Doerfert         OMPInfoCache.OMPBuilder.getOrCreateRuntimeFunction(
3591d9659bf6SJohannes Doerfert             M, OMPRTL___kmpc_kernel_parallel);
3592d9659bf6SJohannes Doerfert     Instruction *IsActiveWorker = CallInst::Create(
3593d9659bf6SJohannes Doerfert         KernelParallelFn, {WorkFnAI}, "worker.is_active", StateMachineBeginBB);
3594d9659bf6SJohannes Doerfert     IsActiveWorker->setDebugLoc(DLoc);
3595d9659bf6SJohannes Doerfert     Instruction *WorkFn = new LoadInst(VoidPtrTy, WorkFnAI, "worker.work_fn",
3596d9659bf6SJohannes Doerfert                                        StateMachineBeginBB);
3597d9659bf6SJohannes Doerfert     WorkFn->setDebugLoc(DLoc);
3598d9659bf6SJohannes Doerfert 
3599d9659bf6SJohannes Doerfert     FunctionType *ParallelRegionFnTy = FunctionType::get(
3600d9659bf6SJohannes Doerfert         Type::getVoidTy(Ctx), {Type::getInt16Ty(Ctx), Type::getInt32Ty(Ctx)},
3601d9659bf6SJohannes Doerfert         false);
3602d9659bf6SJohannes Doerfert     Value *WorkFnCast = BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
3603d9659bf6SJohannes Doerfert         WorkFn, ParallelRegionFnTy->getPointerTo(), "worker.work_fn.addr_cast",
3604d9659bf6SJohannes Doerfert         StateMachineBeginBB);
3605d9659bf6SJohannes Doerfert 
3606d9659bf6SJohannes Doerfert     Instruction *IsDone =
3607d9659bf6SJohannes Doerfert         ICmpInst::Create(ICmpInst::ICmp, llvm::CmpInst::ICMP_EQ, WorkFn,
3608d9659bf6SJohannes Doerfert                          Constant::getNullValue(VoidPtrTy), "worker.is_done",
3609d9659bf6SJohannes Doerfert                          StateMachineBeginBB);
3610d9659bf6SJohannes Doerfert     IsDone->setDebugLoc(DLoc);
3611d9659bf6SJohannes Doerfert     BranchInst::Create(StateMachineFinishedBB, StateMachineIsActiveCheckBB,
3612d9659bf6SJohannes Doerfert                        IsDone, StateMachineBeginBB)
3613d9659bf6SJohannes Doerfert         ->setDebugLoc(DLoc);
3614d9659bf6SJohannes Doerfert 
3615d9659bf6SJohannes Doerfert     BranchInst::Create(StateMachineIfCascadeCurrentBB,
3616d9659bf6SJohannes Doerfert                        StateMachineDoneBarrierBB, IsActiveWorker,
3617d9659bf6SJohannes Doerfert                        StateMachineIsActiveCheckBB)
3618d9659bf6SJohannes Doerfert         ->setDebugLoc(DLoc);
3619d9659bf6SJohannes Doerfert 
3620d9659bf6SJohannes Doerfert     Value *ZeroArg =
3621d9659bf6SJohannes Doerfert         Constant::getNullValue(ParallelRegionFnTy->getParamType(0));
3622d9659bf6SJohannes Doerfert 
3623d9659bf6SJohannes Doerfert     // Now that we have most of the CFG skeleton it is time for the if-cascade
3624d9659bf6SJohannes Doerfert     // that checks the function pointer we got from the runtime against the
3625d9659bf6SJohannes Doerfert     // parallel regions we expect, if there are any.
3626c11ebfeaSJoseph Huber     for (int I = 0, E = ReachedKnownParallelRegions.size(); I < E; ++I) {
3627c11ebfeaSJoseph Huber       auto *ParallelRegion = ReachedKnownParallelRegions[I];
3628d9659bf6SJohannes Doerfert       BasicBlock *PRExecuteBB = BasicBlock::Create(
3629d9659bf6SJohannes Doerfert           Ctx, "worker_state_machine.parallel_region.execute", Kernel,
3630d9659bf6SJohannes Doerfert           StateMachineEndParallelBB);
3631d9659bf6SJohannes Doerfert       CallInst::Create(ParallelRegion, {ZeroArg, GTid}, "", PRExecuteBB)
3632d9659bf6SJohannes Doerfert           ->setDebugLoc(DLoc);
3633d9659bf6SJohannes Doerfert       BranchInst::Create(StateMachineEndParallelBB, PRExecuteBB)
3634d9659bf6SJohannes Doerfert           ->setDebugLoc(DLoc);
3635d9659bf6SJohannes Doerfert 
3636d9659bf6SJohannes Doerfert       BasicBlock *PRNextBB =
3637d9659bf6SJohannes Doerfert           BasicBlock::Create(Ctx, "worker_state_machine.parallel_region.check",
3638d9659bf6SJohannes Doerfert                              Kernel, StateMachineEndParallelBB);
3639d9659bf6SJohannes Doerfert 
3640d9659bf6SJohannes Doerfert       // Check if we need to compare the pointer at all or if we can just
3641d9659bf6SJohannes Doerfert       // call the parallel region function.
3642d9659bf6SJohannes Doerfert       Value *IsPR;
3643c11ebfeaSJoseph Huber       if (I + 1 < E || !ReachedUnknownParallelRegions.empty()) {
3644d9659bf6SJohannes Doerfert         Instruction *CmpI = ICmpInst::Create(
3645d9659bf6SJohannes Doerfert             ICmpInst::ICmp, llvm::CmpInst::ICMP_EQ, WorkFnCast, ParallelRegion,
3646d9659bf6SJohannes Doerfert             "worker.check_parallel_region", StateMachineIfCascadeCurrentBB);
3647d9659bf6SJohannes Doerfert         CmpI->setDebugLoc(DLoc);
3648d9659bf6SJohannes Doerfert         IsPR = CmpI;
3649d9659bf6SJohannes Doerfert       } else {
3650d9659bf6SJohannes Doerfert         IsPR = ConstantInt::getTrue(Ctx);
3651d9659bf6SJohannes Doerfert       }
3652d9659bf6SJohannes Doerfert 
3653d9659bf6SJohannes Doerfert       BranchInst::Create(PRExecuteBB, PRNextBB, IsPR,
3654d9659bf6SJohannes Doerfert                          StateMachineIfCascadeCurrentBB)
3655d9659bf6SJohannes Doerfert           ->setDebugLoc(DLoc);
3656d9659bf6SJohannes Doerfert       StateMachineIfCascadeCurrentBB = PRNextBB;
3657d9659bf6SJohannes Doerfert     }
3658d9659bf6SJohannes Doerfert 
3659d9659bf6SJohannes Doerfert     // At the end of the if-cascade we place the indirect function pointer call
3660d9659bf6SJohannes Doerfert     // in case we might need it, that is if there can be parallel regions we
3661d9659bf6SJohannes Doerfert     // have not handled in the if-cascade above.
3662d9659bf6SJohannes Doerfert     if (!ReachedUnknownParallelRegions.empty()) {
3663d9659bf6SJohannes Doerfert       StateMachineIfCascadeCurrentBB->setName(
3664d9659bf6SJohannes Doerfert           "worker_state_machine.parallel_region.fallback.execute");
3665d9659bf6SJohannes Doerfert       CallInst::Create(ParallelRegionFnTy, WorkFnCast, {ZeroArg, GTid}, "",
3666d9659bf6SJohannes Doerfert                        StateMachineIfCascadeCurrentBB)
3667d9659bf6SJohannes Doerfert           ->setDebugLoc(DLoc);
3668d9659bf6SJohannes Doerfert     }
3669d9659bf6SJohannes Doerfert     BranchInst::Create(StateMachineEndParallelBB,
3670d9659bf6SJohannes Doerfert                        StateMachineIfCascadeCurrentBB)
3671d9659bf6SJohannes Doerfert         ->setDebugLoc(DLoc);
3672d9659bf6SJohannes Doerfert 
3673d9659bf6SJohannes Doerfert     CallInst::Create(OMPInfoCache.OMPBuilder.getOrCreateRuntimeFunction(
3674d9659bf6SJohannes Doerfert                          M, OMPRTL___kmpc_kernel_end_parallel),
3675d9659bf6SJohannes Doerfert                      {}, "", StateMachineEndParallelBB)
3676d9659bf6SJohannes Doerfert         ->setDebugLoc(DLoc);
3677d9659bf6SJohannes Doerfert     BranchInst::Create(StateMachineDoneBarrierBB, StateMachineEndParallelBB)
3678d9659bf6SJohannes Doerfert         ->setDebugLoc(DLoc);
3679d9659bf6SJohannes Doerfert 
3680d9659bf6SJohannes Doerfert     CallInst::Create(BarrierFn, {Ident, GTid}, "", StateMachineDoneBarrierBB)
3681d9659bf6SJohannes Doerfert         ->setDebugLoc(DLoc);
3682d9659bf6SJohannes Doerfert     BranchInst::Create(StateMachineBeginBB, StateMachineDoneBarrierBB)
3683d9659bf6SJohannes Doerfert         ->setDebugLoc(DLoc);
3684d9659bf6SJohannes Doerfert 
3685d9659bf6SJohannes Doerfert     return ChangeStatus::CHANGED;
3686d9659bf6SJohannes Doerfert   }
3687d9659bf6SJohannes Doerfert 
3688d9659bf6SJohannes Doerfert   /// Fixpoint iteration update function. Will be called every time a dependence
3689d9659bf6SJohannes Doerfert   /// changed its state (and in the beginning).
3690d9659bf6SJohannes Doerfert   ChangeStatus updateImpl(Attributor &A) override {
3691d9659bf6SJohannes Doerfert     KernelInfoState StateBefore = getState();
3692d9659bf6SJohannes Doerfert 
3693514c033dSJohannes Doerfert     // Callback to check a read/write instruction.
3694514c033dSJohannes Doerfert     auto CheckRWInst = [&](Instruction &I) {
3695514c033dSJohannes Doerfert       // We handle calls later.
3696514c033dSJohannes Doerfert       if (isa<CallBase>(I))
3697514c033dSJohannes Doerfert         return true;
3698514c033dSJohannes Doerfert       // We only care about write effects.
3699514c033dSJohannes Doerfert       if (!I.mayWriteToMemory())
3700514c033dSJohannes Doerfert         return true;
3701514c033dSJohannes Doerfert       if (auto *SI = dyn_cast<StoreInst>(&I)) {
3702514c033dSJohannes Doerfert         SmallVector<const Value *> Objects;
3703514c033dSJohannes Doerfert         getUnderlyingObjects(SI->getPointerOperand(), Objects);
3704514c033dSJohannes Doerfert         if (llvm::all_of(Objects,
3705514c033dSJohannes Doerfert                          [](const Value *Obj) { return isa<AllocaInst>(Obj); }))
3706514c033dSJohannes Doerfert           return true;
370729a3e3ddSGiorgis Georgakoudis         // Check for AAHeapToStack moved objects which must not be guarded.
370829a3e3ddSGiorgis Georgakoudis         auto &HS = A.getAAFor<AAHeapToStack>(
370929a3e3ddSGiorgis Georgakoudis             *this, IRPosition::function(*I.getFunction()),
3710e6e440aeSJohannes Doerfert             DepClassTy::OPTIONAL);
371129a3e3ddSGiorgis Georgakoudis         if (llvm::all_of(Objects, [&HS](const Value *Obj) {
371229a3e3ddSGiorgis Georgakoudis               auto *CB = dyn_cast<CallBase>(Obj);
371329a3e3ddSGiorgis Georgakoudis               if (!CB)
371429a3e3ddSGiorgis Georgakoudis                 return false;
371529a3e3ddSGiorgis Georgakoudis               return HS.isAssumedHeapToStack(*CB);
371629a3e3ddSGiorgis Georgakoudis             })) {
371729a3e3ddSGiorgis Georgakoudis           return true;
3718514c033dSJohannes Doerfert         }
371929a3e3ddSGiorgis Georgakoudis       }
372029a3e3ddSGiorgis Georgakoudis 
372129a3e3ddSGiorgis Georgakoudis       // Insert instruction that needs guarding.
3722514c033dSJohannes Doerfert       SPMDCompatibilityTracker.insert(&I);
3723514c033dSJohannes Doerfert       return true;
3724514c033dSJohannes Doerfert     };
3725792aac98SJohannes Doerfert 
3726792aac98SJohannes Doerfert     bool UsedAssumedInformationInCheckRWInst = false;
372797387fdfSJohannes Doerfert     if (!SPMDCompatibilityTracker.isAtFixpoint())
3728792aac98SJohannes Doerfert       if (!A.checkForAllReadWriteInstructions(
3729792aac98SJohannes Doerfert               CheckRWInst, *this, UsedAssumedInformationInCheckRWInst))
3730514c033dSJohannes Doerfert         SPMDCompatibilityTracker.indicatePessimisticFixpoint();
3731514c033dSJohannes Doerfert 
3732058c312aSJoseph Huber     bool UsedAssumedInformationFromReachingKernels = false;
3733e97e0a4fSShilei Tian     if (!IsKernelEntry) {
3734e97e0a4fSShilei Tian       updateParallelLevels(A);
373529a3e3ddSGiorgis Georgakoudis 
3736058c312aSJoseph Huber       bool AllReachingKernelsKnown = true;
3737058c312aSJoseph Huber       updateReachingKernelEntries(A, AllReachingKernelsKnown);
3738058c312aSJoseph Huber       UsedAssumedInformationFromReachingKernels = !AllReachingKernelsKnown;
3739058c312aSJoseph Huber 
374029a3e3ddSGiorgis Georgakoudis       if (!ParallelLevels.isValidState())
374129a3e3ddSGiorgis Georgakoudis         SPMDCompatibilityTracker.indicatePessimisticFixpoint();
3742058c312aSJoseph Huber       else if (!ReachingKernelEntries.isValidState())
3743058c312aSJoseph Huber         SPMDCompatibilityTracker.indicatePessimisticFixpoint();
3744058c312aSJoseph Huber       else if (!SPMDCompatibilityTracker.empty()) {
3745058c312aSJoseph Huber         // Check if all reaching kernels agree on the mode as we can otherwise
3746058c312aSJoseph Huber         // not guard instructions. We might not be sure about the mode so we
3747058c312aSJoseph Huber         // we cannot fix the internal spmd-zation state either.
3748058c312aSJoseph Huber         int SPMD = 0, Generic = 0;
3749058c312aSJoseph Huber         for (auto *Kernel : ReachingKernelEntries) {
3750058c312aSJoseph Huber           auto &CBAA = A.getAAFor<AAKernelInfo>(
3751058c312aSJoseph Huber               *this, IRPosition::function(*Kernel), DepClassTy::OPTIONAL);
3752058c312aSJoseph Huber           if (CBAA.SPMDCompatibilityTracker.isValidState() &&
3753058c312aSJoseph Huber               CBAA.SPMDCompatibilityTracker.isAssumed())
3754058c312aSJoseph Huber             ++SPMD;
3755058c312aSJoseph Huber           else
3756058c312aSJoseph Huber             ++Generic;
3757058c312aSJoseph Huber           if (!CBAA.SPMDCompatibilityTracker.isAtFixpoint())
3758058c312aSJoseph Huber             UsedAssumedInformationFromReachingKernels = true;
3759058c312aSJoseph Huber         }
3760058c312aSJoseph Huber         if (SPMD != 0 && Generic != 0)
3761058c312aSJoseph Huber           SPMDCompatibilityTracker.indicatePessimisticFixpoint();
3762058c312aSJoseph Huber       }
3763e97e0a4fSShilei Tian     }
3764ca662297SShilei Tian 
3765d9659bf6SJohannes Doerfert     // Callback to check a call instruction.
3766d61aac76SJohannes Doerfert     bool AllParallelRegionStatesWereFixed = true;
376797387fdfSJohannes Doerfert     bool AllSPMDStatesWereFixed = true;
3768d9659bf6SJohannes Doerfert     auto CheckCallInst = [&](Instruction &I) {
3769d9659bf6SJohannes Doerfert       auto &CB = cast<CallBase>(I);
3770d9659bf6SJohannes Doerfert       auto &CBAA = A.getAAFor<AAKernelInfo>(
3771d9659bf6SJohannes Doerfert           *this, IRPosition::callsite_function(CB), DepClassTy::OPTIONAL);
3772d9659bf6SJohannes Doerfert       getState() ^= CBAA.getState();
377397387fdfSJohannes Doerfert       AllSPMDStatesWereFixed &= CBAA.SPMDCompatibilityTracker.isAtFixpoint();
3774d61aac76SJohannes Doerfert       AllParallelRegionStatesWereFixed &=
3775d61aac76SJohannes Doerfert           CBAA.ReachedKnownParallelRegions.isAtFixpoint();
3776d61aac76SJohannes Doerfert       AllParallelRegionStatesWereFixed &=
3777d61aac76SJohannes Doerfert           CBAA.ReachedUnknownParallelRegions.isAtFixpoint();
3778d9659bf6SJohannes Doerfert       return true;
3779d9659bf6SJohannes Doerfert     };
3780d9659bf6SJohannes Doerfert 
3781792aac98SJohannes Doerfert     bool UsedAssumedInformationInCheckCallInst = false;
3782792aac98SJohannes Doerfert     if (!A.checkForAllCallLikeInstructions(
3783c6457dcaSJohannes Doerfert             CheckCallInst, *this, UsedAssumedInformationInCheckCallInst)) {
3784e6e440aeSJohannes Doerfert       LLVM_DEBUG(dbgs() << TAG
3785e6e440aeSJohannes Doerfert                         << "Failed to visit all call-like instructions!\n";);
3786d9659bf6SJohannes Doerfert       return indicatePessimisticFixpoint();
3787c6457dcaSJohannes Doerfert     }
3788d9659bf6SJohannes Doerfert 
3789d61aac76SJohannes Doerfert     // If we haven't used any assumed information for the reached parallel
3790d61aac76SJohannes Doerfert     // region states we can fix it.
3791d61aac76SJohannes Doerfert     if (!UsedAssumedInformationInCheckCallInst &&
3792d61aac76SJohannes Doerfert         AllParallelRegionStatesWereFixed) {
3793d61aac76SJohannes Doerfert       ReachedKnownParallelRegions.indicateOptimisticFixpoint();
3794d61aac76SJohannes Doerfert       ReachedUnknownParallelRegions.indicateOptimisticFixpoint();
3795d61aac76SJohannes Doerfert     }
3796d61aac76SJohannes Doerfert 
3797d61aac76SJohannes Doerfert     // If we are sure there are no parallel regions in the kernel we do not
3798d61aac76SJohannes Doerfert     // want SPMD mode.
3799d61aac76SJohannes Doerfert     if (IsKernelEntry && ReachedUnknownParallelRegions.isAtFixpoint() &&
3800d61aac76SJohannes Doerfert         ReachedKnownParallelRegions.isAtFixpoint() &&
3801d61aac76SJohannes Doerfert         ReachedUnknownParallelRegions.isValidState() &&
3802d61aac76SJohannes Doerfert         ReachedKnownParallelRegions.isValidState() &&
3803d61aac76SJohannes Doerfert         !mayContainParallelRegion())
3804d61aac76SJohannes Doerfert       SPMDCompatibilityTracker.indicatePessimisticFixpoint();
3805d61aac76SJohannes Doerfert 
380697387fdfSJohannes Doerfert     // If we haven't used any assumed information for the SPMD state we can fix
380797387fdfSJohannes Doerfert     // it.
380897387fdfSJohannes Doerfert     if (!UsedAssumedInformationInCheckRWInst &&
3809058c312aSJoseph Huber         !UsedAssumedInformationInCheckCallInst &&
3810058c312aSJoseph Huber         !UsedAssumedInformationFromReachingKernels && AllSPMDStatesWereFixed)
381197387fdfSJohannes Doerfert       SPMDCompatibilityTracker.indicateOptimisticFixpoint();
381297387fdfSJohannes Doerfert 
3813d9659bf6SJohannes Doerfert     return StateBefore == getState() ? ChangeStatus::UNCHANGED
3814d9659bf6SJohannes Doerfert                                      : ChangeStatus::CHANGED;
3815d9659bf6SJohannes Doerfert   }
3816ca662297SShilei Tian 
3817ca662297SShilei Tian private:
3818ca662297SShilei Tian   /// Update info regarding reaching kernels.
3819058c312aSJoseph Huber   void updateReachingKernelEntries(Attributor &A,
3820058c312aSJoseph Huber                                    bool &AllReachingKernelsKnown) {
3821ca662297SShilei Tian     auto PredCallSite = [&](AbstractCallSite ACS) {
3822ca662297SShilei Tian       Function *Caller = ACS.getInstruction()->getFunction();
3823ca662297SShilei Tian 
3824ca662297SShilei Tian       assert(Caller && "Caller is nullptr");
3825ca662297SShilei Tian 
3826d3454ee8SShilei Tian       auto &CAA = A.getOrCreateAAFor<AAKernelInfo>(
3827d3454ee8SShilei Tian           IRPosition::function(*Caller), this, DepClassTy::REQUIRED);
3828ca662297SShilei Tian       if (CAA.ReachingKernelEntries.isValidState()) {
3829ca662297SShilei Tian         ReachingKernelEntries ^= CAA.ReachingKernelEntries;
3830ca662297SShilei Tian         return true;
3831ca662297SShilei Tian       }
3832ca662297SShilei Tian 
3833ca662297SShilei Tian       // We lost track of the caller of the associated function, any kernel
3834ca662297SShilei Tian       // could reach now.
3835ca662297SShilei Tian       ReachingKernelEntries.indicatePessimisticFixpoint();
3836ca662297SShilei Tian 
3837ca662297SShilei Tian       return true;
3838ca662297SShilei Tian     };
3839ca662297SShilei Tian 
3840ca662297SShilei Tian     if (!A.checkForAllCallSites(PredCallSite, *this,
3841ca662297SShilei Tian                                 true /* RequireAllCallSites */,
3842058c312aSJoseph Huber                                 AllReachingKernelsKnown))
3843ca662297SShilei Tian       ReachingKernelEntries.indicatePessimisticFixpoint();
3844ca662297SShilei Tian   }
3845e97e0a4fSShilei Tian 
3846e97e0a4fSShilei Tian   /// Update info regarding parallel levels.
3847e97e0a4fSShilei Tian   void updateParallelLevels(Attributor &A) {
3848e97e0a4fSShilei Tian     auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
3849e97e0a4fSShilei Tian     OMPInformationCache::RuntimeFunctionInfo &Parallel51RFI =
3850e97e0a4fSShilei Tian         OMPInfoCache.RFIs[OMPRTL___kmpc_parallel_51];
3851e97e0a4fSShilei Tian 
3852e97e0a4fSShilei Tian     auto PredCallSite = [&](AbstractCallSite ACS) {
3853e97e0a4fSShilei Tian       Function *Caller = ACS.getInstruction()->getFunction();
3854e97e0a4fSShilei Tian 
3855e97e0a4fSShilei Tian       assert(Caller && "Caller is nullptr");
3856e97e0a4fSShilei Tian 
3857e97e0a4fSShilei Tian       auto &CAA =
3858e97e0a4fSShilei Tian           A.getOrCreateAAFor<AAKernelInfo>(IRPosition::function(*Caller));
3859e97e0a4fSShilei Tian       if (CAA.ParallelLevels.isValidState()) {
3860e97e0a4fSShilei Tian         // Any function that is called by `__kmpc_parallel_51` will not be
3861e97e0a4fSShilei Tian         // folded as the parallel level in the function is updated. In order to
3862e97e0a4fSShilei Tian         // get it right, all the analysis would depend on the implentation. That
3863e97e0a4fSShilei Tian         // said, if in the future any change to the implementation, the analysis
3864e97e0a4fSShilei Tian         // could be wrong. As a consequence, we are just conservative here.
3865e97e0a4fSShilei Tian         if (Caller == Parallel51RFI.Declaration) {
3866e97e0a4fSShilei Tian           ParallelLevels.indicatePessimisticFixpoint();
3867e97e0a4fSShilei Tian           return true;
3868e97e0a4fSShilei Tian         }
3869e97e0a4fSShilei Tian 
3870e97e0a4fSShilei Tian         ParallelLevels ^= CAA.ParallelLevels;
3871e97e0a4fSShilei Tian 
3872e97e0a4fSShilei Tian         return true;
3873e97e0a4fSShilei Tian       }
3874e97e0a4fSShilei Tian 
3875e97e0a4fSShilei Tian       // We lost track of the caller of the associated function, any kernel
3876e97e0a4fSShilei Tian       // could reach now.
3877e97e0a4fSShilei Tian       ParallelLevels.indicatePessimisticFixpoint();
3878e97e0a4fSShilei Tian 
3879e97e0a4fSShilei Tian       return true;
3880e97e0a4fSShilei Tian     };
3881e97e0a4fSShilei Tian 
3882e97e0a4fSShilei Tian     bool AllCallSitesKnown = true;
3883e97e0a4fSShilei Tian     if (!A.checkForAllCallSites(PredCallSite, *this,
3884e97e0a4fSShilei Tian                                 true /* RequireAllCallSites */,
3885e97e0a4fSShilei Tian                                 AllCallSitesKnown))
3886e97e0a4fSShilei Tian       ParallelLevels.indicatePessimisticFixpoint();
3887e97e0a4fSShilei Tian   }
3888d9659bf6SJohannes Doerfert };
3889d9659bf6SJohannes Doerfert 
3890d9659bf6SJohannes Doerfert /// The call site kernel info abstract attribute, basically, what can we say
3891d9659bf6SJohannes Doerfert /// about a call site with regards to the KernelInfoState. For now this simply
3892d9659bf6SJohannes Doerfert /// forwards the information from the callee.
3893d9659bf6SJohannes Doerfert struct AAKernelInfoCallSite : AAKernelInfo {
3894d9659bf6SJohannes Doerfert   AAKernelInfoCallSite(const IRPosition &IRP, Attributor &A)
3895d9659bf6SJohannes Doerfert       : AAKernelInfo(IRP, A) {}
3896d9659bf6SJohannes Doerfert 
3897d9659bf6SJohannes Doerfert   /// See AbstractAttribute::initialize(...).
3898d9659bf6SJohannes Doerfert   void initialize(Attributor &A) override {
3899d9659bf6SJohannes Doerfert     AAKernelInfo::initialize(A);
3900d9659bf6SJohannes Doerfert 
3901d9659bf6SJohannes Doerfert     CallBase &CB = cast<CallBase>(getAssociatedValue());
3902d9659bf6SJohannes Doerfert     Function *Callee = getAssociatedFunction();
3903d9659bf6SJohannes Doerfert 
3904e52937ebSJoseph Huber     auto &AssumptionAA = A.getAAFor<AAAssumptionInfo>(
3905e52937ebSJoseph Huber         *this, IRPosition::callsite_function(CB), DepClassTy::OPTIONAL);
3906d9659bf6SJohannes Doerfert 
3907514c033dSJohannes Doerfert     // Check for SPMD-mode assumptions.
3908e52937ebSJoseph Huber     if (AssumptionAA.hasAssumption("ompx_spmd_amenable")) {
3909514c033dSJohannes Doerfert       SPMDCompatibilityTracker.indicateOptimisticFixpoint();
39109e2fc0baSJoseph Huber       indicateOptimisticFixpoint();
39119e2fc0baSJoseph Huber     }
3912514c033dSJohannes Doerfert 
3913d9659bf6SJohannes Doerfert     // First weed out calls we do not care about, that is readonly/readnone
3914d9659bf6SJohannes Doerfert     // calls, intrinsics, and "no_openmp" calls. Neither of these can reach a
3915d9659bf6SJohannes Doerfert     // parallel region or anything else we are looking for.
3916d9659bf6SJohannes Doerfert     if (!CB.mayWriteToMemory() || isa<IntrinsicInst>(CB)) {
3917d9659bf6SJohannes Doerfert       indicateOptimisticFixpoint();
3918d9659bf6SJohannes Doerfert       return;
3919d9659bf6SJohannes Doerfert     }
3920d9659bf6SJohannes Doerfert 
3921d9659bf6SJohannes Doerfert     // Next we check if we know the callee. If it is a known OpenMP function
3922d9659bf6SJohannes Doerfert     // we will handle them explicitly in the switch below. If it is not, we
3923d9659bf6SJohannes Doerfert     // will use an AAKernelInfo object on the callee to gather information and
3924d9659bf6SJohannes Doerfert     // merge that into the current state. The latter happens in the updateImpl.
3925d9659bf6SJohannes Doerfert     auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
3926d9659bf6SJohannes Doerfert     const auto &It = OMPInfoCache.RuntimeFunctionIDMap.find(Callee);
3927d9659bf6SJohannes Doerfert     if (It == OMPInfoCache.RuntimeFunctionIDMap.end()) {
3928d9659bf6SJohannes Doerfert       // Unknown caller or declarations are not analyzable, we give up.
3929d9659bf6SJohannes Doerfert       if (!Callee || !A.isFunctionIPOAmendable(*Callee)) {
3930d9659bf6SJohannes Doerfert 
3931d9659bf6SJohannes Doerfert         // Unknown callees might contain parallel regions, except if they have
3932d9659bf6SJohannes Doerfert         // an appropriate assumption attached.
3933e52937ebSJoseph Huber         if (!(AssumptionAA.hasAssumption("omp_no_openmp") ||
3934e52937ebSJoseph Huber               AssumptionAA.hasAssumption("omp_no_parallelism")))
3935d9659bf6SJohannes Doerfert           ReachedUnknownParallelRegions.insert(&CB);
3936d9659bf6SJohannes Doerfert 
3937514c033dSJohannes Doerfert         // If SPMDCompatibilityTracker is not fixed, we need to give up on the
3938514c033dSJohannes Doerfert         // idea we can run something unknown in SPMD-mode.
393929a3e3ddSGiorgis Georgakoudis         if (!SPMDCompatibilityTracker.isAtFixpoint()) {
394029a3e3ddSGiorgis Georgakoudis           SPMDCompatibilityTracker.indicatePessimisticFixpoint();
3941514c033dSJohannes Doerfert           SPMDCompatibilityTracker.insert(&CB);
394229a3e3ddSGiorgis Georgakoudis         }
3943514c033dSJohannes Doerfert 
3944d9659bf6SJohannes Doerfert         // We have updated the state for this unknown call properly, there won't
3945d9659bf6SJohannes Doerfert         // be any change so we indicate a fixpoint.
3946d9659bf6SJohannes Doerfert         indicateOptimisticFixpoint();
3947d9659bf6SJohannes Doerfert       }
3948d9659bf6SJohannes Doerfert       // If the callee is known and can be used in IPO, we will update the state
3949d9659bf6SJohannes Doerfert       // based on the callee state in updateImpl.
3950d9659bf6SJohannes Doerfert       return;
3951d9659bf6SJohannes Doerfert     }
3952d9659bf6SJohannes Doerfert 
3953d9659bf6SJohannes Doerfert     const unsigned int WrapperFunctionArgNo = 6;
3954d9659bf6SJohannes Doerfert     RuntimeFunction RF = It->getSecond();
3955d9659bf6SJohannes Doerfert     switch (RF) {
3956514c033dSJohannes Doerfert     // All the functions we know are compatible with SPMD mode.
3957514c033dSJohannes Doerfert     case OMPRTL___kmpc_is_spmd_exec_mode:
395887ce7e65SJoseph Huber     case OMPRTL___kmpc_distribute_static_fini:
3959514c033dSJohannes Doerfert     case OMPRTL___kmpc_for_static_fini:
3960514c033dSJohannes Doerfert     case OMPRTL___kmpc_global_thread_num:
39615ab6aeddSJose M Monsalve Diaz     case OMPRTL___kmpc_get_hardware_num_threads_in_block:
39625ab6aeddSJose M Monsalve Diaz     case OMPRTL___kmpc_get_hardware_num_blocks:
3963514c033dSJohannes Doerfert     case OMPRTL___kmpc_single:
3964514c033dSJohannes Doerfert     case OMPRTL___kmpc_end_single:
3965514c033dSJohannes Doerfert     case OMPRTL___kmpc_master:
3966514c033dSJohannes Doerfert     case OMPRTL___kmpc_end_master:
3967514c033dSJohannes Doerfert     case OMPRTL___kmpc_barrier:
3968744aa09fSJoseph Huber     case OMPRTL___kmpc_nvptx_parallel_reduce_nowait_v2:
3969744aa09fSJoseph Huber     case OMPRTL___kmpc_nvptx_teams_reduce_nowait_v2:
3970744aa09fSJoseph Huber     case OMPRTL___kmpc_nvptx_end_reduce_nowait:
3971514c033dSJohannes Doerfert       break;
397287ce7e65SJoseph Huber     case OMPRTL___kmpc_distribute_static_init_4:
397387ce7e65SJoseph Huber     case OMPRTL___kmpc_distribute_static_init_4u:
397487ce7e65SJoseph Huber     case OMPRTL___kmpc_distribute_static_init_8:
397587ce7e65SJoseph Huber     case OMPRTL___kmpc_distribute_static_init_8u:
3976514c033dSJohannes Doerfert     case OMPRTL___kmpc_for_static_init_4:
3977514c033dSJohannes Doerfert     case OMPRTL___kmpc_for_static_init_4u:
3978514c033dSJohannes Doerfert     case OMPRTL___kmpc_for_static_init_8:
3979514c033dSJohannes Doerfert     case OMPRTL___kmpc_for_static_init_8u: {
3980514c033dSJohannes Doerfert       // Check the schedule and allow static schedule in SPMD mode.
3981514c033dSJohannes Doerfert       unsigned ScheduleArgOpNo = 2;
3982514c033dSJohannes Doerfert       auto *ScheduleTypeCI =
3983514c033dSJohannes Doerfert           dyn_cast<ConstantInt>(CB.getArgOperand(ScheduleArgOpNo));
3984514c033dSJohannes Doerfert       unsigned ScheduleTypeVal =
3985514c033dSJohannes Doerfert           ScheduleTypeCI ? ScheduleTypeCI->getZExtValue() : 0;
3986514c033dSJohannes Doerfert       switch (OMPScheduleType(ScheduleTypeVal)) {
3987514c033dSJohannes Doerfert       case OMPScheduleType::Static:
3988514c033dSJohannes Doerfert       case OMPScheduleType::StaticChunked:
3989514c033dSJohannes Doerfert       case OMPScheduleType::Distribute:
3990514c033dSJohannes Doerfert       case OMPScheduleType::DistributeChunked:
3991514c033dSJohannes Doerfert         break;
3992514c033dSJohannes Doerfert       default:
399329a3e3ddSGiorgis Georgakoudis         SPMDCompatibilityTracker.indicatePessimisticFixpoint();
3994514c033dSJohannes Doerfert         SPMDCompatibilityTracker.insert(&CB);
3995514c033dSJohannes Doerfert         break;
3996514c033dSJohannes Doerfert       };
3997514c033dSJohannes Doerfert     } break;
3998d9659bf6SJohannes Doerfert     case OMPRTL___kmpc_target_init:
3999d9659bf6SJohannes Doerfert       KernelInitCB = &CB;
4000d9659bf6SJohannes Doerfert       break;
4001d9659bf6SJohannes Doerfert     case OMPRTL___kmpc_target_deinit:
4002d9659bf6SJohannes Doerfert       KernelDeinitCB = &CB;
4003d9659bf6SJohannes Doerfert       break;
4004d9659bf6SJohannes Doerfert     case OMPRTL___kmpc_parallel_51:
4005d9659bf6SJohannes Doerfert       if (auto *ParallelRegion = dyn_cast<Function>(
4006d9659bf6SJohannes Doerfert               CB.getArgOperand(WrapperFunctionArgNo)->stripPointerCasts())) {
4007d9659bf6SJohannes Doerfert         ReachedKnownParallelRegions.insert(ParallelRegion);
4008d9659bf6SJohannes Doerfert         break;
4009d9659bf6SJohannes Doerfert       }
4010d9659bf6SJohannes Doerfert       // The condition above should usually get the parallel region function
4011d9659bf6SJohannes Doerfert       // pointer and record it. In the off chance it doesn't we assume the
4012d9659bf6SJohannes Doerfert       // worst.
4013d9659bf6SJohannes Doerfert       ReachedUnknownParallelRegions.insert(&CB);
4014d9659bf6SJohannes Doerfert       break;
4015d9659bf6SJohannes Doerfert     case OMPRTL___kmpc_omp_task:
4016d9659bf6SJohannes Doerfert       // We do not look into tasks right now, just give up.
40179ea5b972SJoseph Huber       SPMDCompatibilityTracker.indicatePessimisticFixpoint();
4018514c033dSJohannes Doerfert       SPMDCompatibilityTracker.insert(&CB);
4019d9659bf6SJohannes Doerfert       ReachedUnknownParallelRegions.insert(&CB);
4020c6457dcaSJohannes Doerfert       break;
4021f8c40ed8SGiorgis Georgakoudis     case OMPRTL___kmpc_alloc_shared:
4022f8c40ed8SGiorgis Georgakoudis     case OMPRTL___kmpc_free_shared:
4023f8c40ed8SGiorgis Georgakoudis       // Return without setting a fixpoint, to be resolved in updateImpl.
4024f8c40ed8SGiorgis Georgakoudis       return;
4025d9659bf6SJohannes Doerfert     default:
4026514c033dSJohannes Doerfert       // Unknown OpenMP runtime calls cannot be executed in SPMD-mode,
4027c6457dcaSJohannes Doerfert       // generally. However, they do not hide parallel regions.
40289ea5b972SJoseph Huber       SPMDCompatibilityTracker.indicatePessimisticFixpoint();
4029514c033dSJohannes Doerfert       SPMDCompatibilityTracker.insert(&CB);
4030c6457dcaSJohannes Doerfert       break;
4031d9659bf6SJohannes Doerfert     }
4032d9659bf6SJohannes Doerfert     // All other OpenMP runtime calls will not reach parallel regions so they
4033d9659bf6SJohannes Doerfert     // can be safely ignored for now. Since it is a known OpenMP runtime call we
4034d9659bf6SJohannes Doerfert     // have now modeled all effects and there is no need for any update.
4035d9659bf6SJohannes Doerfert     indicateOptimisticFixpoint();
4036d9659bf6SJohannes Doerfert   }
4037d9659bf6SJohannes Doerfert 
4038d9659bf6SJohannes Doerfert   ChangeStatus updateImpl(Attributor &A) override {
4039d9659bf6SJohannes Doerfert     // TODO: Once we have call site specific value information we can provide
4040d9659bf6SJohannes Doerfert     //       call site specific liveness information and then it makes
4041d9659bf6SJohannes Doerfert     //       sense to specialize attributes for call sites arguments instead of
4042d9659bf6SJohannes Doerfert     //       redirecting requests to the callee argument.
4043d9659bf6SJohannes Doerfert     Function *F = getAssociatedFunction();
4044f8c40ed8SGiorgis Georgakoudis 
4045f8c40ed8SGiorgis Georgakoudis     auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
4046f8c40ed8SGiorgis Georgakoudis     const auto &It = OMPInfoCache.RuntimeFunctionIDMap.find(F);
4047f8c40ed8SGiorgis Georgakoudis 
4048f8c40ed8SGiorgis Georgakoudis     // If F is not a runtime function, propagate the AAKernelInfo of the callee.
4049f8c40ed8SGiorgis Georgakoudis     if (It == OMPInfoCache.RuntimeFunctionIDMap.end()) {
4050d9659bf6SJohannes Doerfert       const IRPosition &FnPos = IRPosition::function(*F);
4051d9659bf6SJohannes Doerfert       auto &FnAA = A.getAAFor<AAKernelInfo>(*this, FnPos, DepClassTy::REQUIRED);
4052d9659bf6SJohannes Doerfert       if (getState() == FnAA.getState())
4053d9659bf6SJohannes Doerfert         return ChangeStatus::UNCHANGED;
4054d9659bf6SJohannes Doerfert       getState() = FnAA.getState();
4055d9659bf6SJohannes Doerfert       return ChangeStatus::CHANGED;
4056d9659bf6SJohannes Doerfert     }
4057f8c40ed8SGiorgis Georgakoudis 
4058f8c40ed8SGiorgis Georgakoudis     // F is a runtime function that allocates or frees memory, check
4059f8c40ed8SGiorgis Georgakoudis     // AAHeapToStack and AAHeapToShared.
4060f8c40ed8SGiorgis Georgakoudis     KernelInfoState StateBefore = getState();
4061f8c40ed8SGiorgis Georgakoudis     assert((It->getSecond() == OMPRTL___kmpc_alloc_shared ||
4062f8c40ed8SGiorgis Georgakoudis             It->getSecond() == OMPRTL___kmpc_free_shared) &&
4063f8c40ed8SGiorgis Georgakoudis            "Expected a __kmpc_alloc_shared or __kmpc_free_shared runtime call");
4064f8c40ed8SGiorgis Georgakoudis 
4065f8c40ed8SGiorgis Georgakoudis     CallBase &CB = cast<CallBase>(getAssociatedValue());
4066f8c40ed8SGiorgis Georgakoudis 
4067f8c40ed8SGiorgis Georgakoudis     auto &HeapToStackAA = A.getAAFor<AAHeapToStack>(
4068f8c40ed8SGiorgis Georgakoudis         *this, IRPosition::function(*CB.getCaller()), DepClassTy::OPTIONAL);
4069f8c40ed8SGiorgis Georgakoudis     auto &HeapToSharedAA = A.getAAFor<AAHeapToShared>(
4070f8c40ed8SGiorgis Georgakoudis         *this, IRPosition::function(*CB.getCaller()), DepClassTy::OPTIONAL);
4071f8c40ed8SGiorgis Georgakoudis 
4072f8c40ed8SGiorgis Georgakoudis     RuntimeFunction RF = It->getSecond();
4073f8c40ed8SGiorgis Georgakoudis 
4074f8c40ed8SGiorgis Georgakoudis     switch (RF) {
4075f8c40ed8SGiorgis Georgakoudis     // If neither HeapToStack nor HeapToShared assume the call is removed,
4076f8c40ed8SGiorgis Georgakoudis     // assume SPMD incompatibility.
4077f8c40ed8SGiorgis Georgakoudis     case OMPRTL___kmpc_alloc_shared:
4078f8c40ed8SGiorgis Georgakoudis       if (!HeapToStackAA.isAssumedHeapToStack(CB) &&
4079f8c40ed8SGiorgis Georgakoudis           !HeapToSharedAA.isAssumedHeapToShared(CB))
4080f8c40ed8SGiorgis Georgakoudis         SPMDCompatibilityTracker.insert(&CB);
4081f8c40ed8SGiorgis Georgakoudis       break;
4082f8c40ed8SGiorgis Georgakoudis     case OMPRTL___kmpc_free_shared:
4083f8c40ed8SGiorgis Georgakoudis       if (!HeapToStackAA.isAssumedHeapToStackRemovedFree(CB) &&
4084f8c40ed8SGiorgis Georgakoudis           !HeapToSharedAA.isAssumedHeapToSharedRemovedFree(CB))
4085f8c40ed8SGiorgis Georgakoudis         SPMDCompatibilityTracker.insert(&CB);
4086f8c40ed8SGiorgis Georgakoudis       break;
4087f8c40ed8SGiorgis Georgakoudis     default:
40889ea5b972SJoseph Huber       SPMDCompatibilityTracker.indicatePessimisticFixpoint();
4089f8c40ed8SGiorgis Georgakoudis       SPMDCompatibilityTracker.insert(&CB);
4090f8c40ed8SGiorgis Georgakoudis     }
4091f8c40ed8SGiorgis Georgakoudis 
4092f8c40ed8SGiorgis Georgakoudis     return StateBefore == getState() ? ChangeStatus::UNCHANGED
4093f8c40ed8SGiorgis Georgakoudis                                      : ChangeStatus::CHANGED;
4094f8c40ed8SGiorgis Georgakoudis   }
4095d9659bf6SJohannes Doerfert };
4096d9659bf6SJohannes Doerfert 
4097ca662297SShilei Tian struct AAFoldRuntimeCall
4098ca662297SShilei Tian     : public StateWrapper<BooleanState, AbstractAttribute> {
4099ca662297SShilei Tian   using Base = StateWrapper<BooleanState, AbstractAttribute>;
4100ca662297SShilei Tian 
4101ca662297SShilei Tian   AAFoldRuntimeCall(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
4102ca662297SShilei Tian 
4103ca662297SShilei Tian   /// Statistics are tracked as part of manifest for now.
4104ca662297SShilei Tian   void trackStatistics() const override {}
4105ca662297SShilei Tian 
4106ca662297SShilei Tian   /// Create an abstract attribute biew for the position \p IRP.
4107ca662297SShilei Tian   static AAFoldRuntimeCall &createForPosition(const IRPosition &IRP,
4108ca662297SShilei Tian                                               Attributor &A);
4109ca662297SShilei Tian 
4110ca662297SShilei Tian   /// See AbstractAttribute::getName()
4111ca662297SShilei Tian   const std::string getName() const override { return "AAFoldRuntimeCall"; }
4112ca662297SShilei Tian 
4113ca662297SShilei Tian   /// See AbstractAttribute::getIdAddr()
4114ca662297SShilei Tian   const char *getIdAddr() const override { return &ID; }
4115ca662297SShilei Tian 
4116ca662297SShilei Tian   /// This function should return true if the type of the \p AA is
4117ca662297SShilei Tian   /// AAFoldRuntimeCall
4118ca662297SShilei Tian   static bool classof(const AbstractAttribute *AA) {
4119ca662297SShilei Tian     return (AA->getIdAddr() == &ID);
4120ca662297SShilei Tian   }
4121ca662297SShilei Tian 
4122ca662297SShilei Tian   static const char ID;
4123ca662297SShilei Tian };
4124ca662297SShilei Tian 
4125ca662297SShilei Tian struct AAFoldRuntimeCallCallSiteReturned : AAFoldRuntimeCall {
4126ca662297SShilei Tian   AAFoldRuntimeCallCallSiteReturned(const IRPosition &IRP, Attributor &A)
4127ca662297SShilei Tian       : AAFoldRuntimeCall(IRP, A) {}
4128ca662297SShilei Tian 
4129ca662297SShilei Tian   /// See AbstractAttribute::getAsStr()
4130ca662297SShilei Tian   const std::string getAsStr() const override {
4131ca662297SShilei Tian     if (!isValidState())
4132ca662297SShilei Tian       return "<invalid>";
4133ca662297SShilei Tian 
4134ca662297SShilei Tian     std::string Str("simplified value: ");
4135ca662297SShilei Tian 
4136ca662297SShilei Tian     if (!SimplifiedValue.hasValue())
4137ca662297SShilei Tian       return Str + std::string("none");
4138ca662297SShilei Tian 
4139ca662297SShilei Tian     if (!SimplifiedValue.getValue())
4140ca662297SShilei Tian       return Str + std::string("nullptr");
4141ca662297SShilei Tian 
4142ca662297SShilei Tian     if (ConstantInt *CI = dyn_cast<ConstantInt>(SimplifiedValue.getValue()))
4143ca662297SShilei Tian       return Str + std::to_string(CI->getSExtValue());
4144ca662297SShilei Tian 
4145ca662297SShilei Tian     return Str + std::string("unknown");
4146ca662297SShilei Tian   }
4147ca662297SShilei Tian 
4148ca662297SShilei Tian   void initialize(Attributor &A) override {
4149cd0dd8ecSJoseph Huber     if (DisableOpenMPOptFolding)
4150cd0dd8ecSJoseph Huber       indicatePessimisticFixpoint();
4151cd0dd8ecSJoseph Huber 
4152ca662297SShilei Tian     Function *Callee = getAssociatedFunction();
4153ca662297SShilei Tian 
4154ca662297SShilei Tian     auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
4155ca662297SShilei Tian     const auto &It = OMPInfoCache.RuntimeFunctionIDMap.find(Callee);
4156ca662297SShilei Tian     assert(It != OMPInfoCache.RuntimeFunctionIDMap.end() &&
4157ca662297SShilei Tian            "Expected a known OpenMP runtime function");
4158ca662297SShilei Tian 
4159ca662297SShilei Tian     RFKind = It->getSecond();
4160ca662297SShilei Tian 
4161ca662297SShilei Tian     CallBase &CB = cast<CallBase>(getAssociatedValue());
4162ca662297SShilei Tian     A.registerSimplificationCallback(
4163ca662297SShilei Tian         IRPosition::callsite_returned(CB),
4164ca662297SShilei Tian         [&](const IRPosition &IRP, const AbstractAttribute *AA,
4165ca662297SShilei Tian             bool &UsedAssumedInformation) -> Optional<Value *> {
4166ca662297SShilei Tian           assert((isValidState() || (SimplifiedValue.hasValue() &&
4167ca662297SShilei Tian                                      SimplifiedValue.getValue() == nullptr)) &&
4168ca662297SShilei Tian                  "Unexpected invalid state!");
4169ca662297SShilei Tian 
4170ca662297SShilei Tian           if (!isAtFixpoint()) {
4171ca662297SShilei Tian             UsedAssumedInformation = true;
4172ca662297SShilei Tian             if (AA)
4173ca662297SShilei Tian               A.recordDependence(*this, *AA, DepClassTy::OPTIONAL);
4174ca662297SShilei Tian           }
4175ca662297SShilei Tian           return SimplifiedValue;
4176ca662297SShilei Tian         });
4177ca662297SShilei Tian   }
4178ca662297SShilei Tian 
4179ca662297SShilei Tian   ChangeStatus updateImpl(Attributor &A) override {
4180ca662297SShilei Tian     ChangeStatus Changed = ChangeStatus::UNCHANGED;
4181ca662297SShilei Tian     switch (RFKind) {
4182ca662297SShilei Tian     case OMPRTL___kmpc_is_spmd_exec_mode:
4183c23da666SShilei Tian       Changed |= foldIsSPMDExecMode(A);
4184ca662297SShilei Tian       break;
4185196fe994SJoseph Huber     case OMPRTL___kmpc_is_generic_main_thread_id:
4186196fe994SJoseph Huber       Changed |= foldIsGenericMainThread(A);
4187196fe994SJoseph Huber       break;
4188e97e0a4fSShilei Tian     case OMPRTL___kmpc_parallel_level:
4189e97e0a4fSShilei Tian       Changed |= foldParallelLevel(A);
4190e97e0a4fSShilei Tian       break;
41915ab6aeddSJose M Monsalve Diaz     case OMPRTL___kmpc_get_hardware_num_threads_in_block:
41925ab6aeddSJose M Monsalve Diaz       Changed = Changed | foldKernelFnAttribute(A, "omp_target_thread_limit");
41935ab6aeddSJose M Monsalve Diaz       break;
41945ab6aeddSJose M Monsalve Diaz     case OMPRTL___kmpc_get_hardware_num_blocks:
41955ab6aeddSJose M Monsalve Diaz       Changed = Changed | foldKernelFnAttribute(A, "omp_target_num_teams");
41965ab6aeddSJose M Monsalve Diaz       break;
4197ca662297SShilei Tian     default:
4198ca662297SShilei Tian       llvm_unreachable("Unhandled OpenMP runtime function!");
4199ca662297SShilei Tian     }
4200ca662297SShilei Tian 
4201ca662297SShilei Tian     return Changed;
4202ca662297SShilei Tian   }
4203ca662297SShilei Tian 
4204ca662297SShilei Tian   ChangeStatus manifest(Attributor &A) override {
4205ca662297SShilei Tian     ChangeStatus Changed = ChangeStatus::UNCHANGED;
4206ca662297SShilei Tian 
4207ca662297SShilei Tian     if (SimplifiedValue.hasValue() && SimplifiedValue.getValue()) {
42087eb899cbSJoseph Huber       Instruction &I = *getCtxI();
42097eb899cbSJoseph Huber       A.changeValueAfterManifest(I, **SimplifiedValue);
42107eb899cbSJoseph Huber       A.deleteAfterManifest(I);
4211196fe994SJoseph Huber 
42127eb899cbSJoseph Huber       CallBase *CB = dyn_cast<CallBase>(&I);
42137eb899cbSJoseph Huber       auto Remark = [&](OptimizationRemark OR) {
42147eb899cbSJoseph Huber         if (auto *C = dyn_cast<ConstantInt>(*SimplifiedValue))
42157eb899cbSJoseph Huber           return OR << "Replacing OpenMP runtime call "
42167eb899cbSJoseph Huber                     << CB->getCalledFunction()->getName() << " with "
42177eb899cbSJoseph Huber                     << ore::NV("FoldedValue", C->getZExtValue()) << ".";
42187eb899cbSJoseph Huber         return OR << "Replacing OpenMP runtime call "
42197eb899cbSJoseph Huber                   << CB->getCalledFunction()->getName() << ".";
42207eb899cbSJoseph Huber       };
42217eb899cbSJoseph Huber 
42227eb899cbSJoseph Huber       if (CB && EnableVerboseRemarks)
42237eb899cbSJoseph Huber         A.emitRemark<OptimizationRemark>(CB, "OMP180", Remark);
42247eb899cbSJoseph Huber 
42257eb899cbSJoseph Huber       LLVM_DEBUG(dbgs() << TAG << "Replacing runtime call: " << I << " with "
4226196fe994SJoseph Huber                         << **SimplifiedValue << "\n");
4227196fe994SJoseph Huber 
4228ca662297SShilei Tian       Changed = ChangeStatus::CHANGED;
4229ca662297SShilei Tian     }
4230ca662297SShilei Tian 
4231ca662297SShilei Tian     return Changed;
4232ca662297SShilei Tian   }
4233ca662297SShilei Tian 
4234ca662297SShilei Tian   ChangeStatus indicatePessimisticFixpoint() override {
4235ca662297SShilei Tian     SimplifiedValue = nullptr;
4236ca662297SShilei Tian     return AAFoldRuntimeCall::indicatePessimisticFixpoint();
4237ca662297SShilei Tian   }
4238ca662297SShilei Tian 
4239ca662297SShilei Tian private:
4240ca662297SShilei Tian   /// Fold __kmpc_is_spmd_exec_mode into a constant if possible.
4241ca662297SShilei Tian   ChangeStatus foldIsSPMDExecMode(Attributor &A) {
4242ca662297SShilei Tian     Optional<Value *> SimplifiedValueBefore = SimplifiedValue;
4243ca662297SShilei Tian 
4244ca662297SShilei Tian     unsigned AssumedSPMDCount = 0, KnownSPMDCount = 0;
4245ca662297SShilei Tian     unsigned AssumedNonSPMDCount = 0, KnownNonSPMDCount = 0;
4246ca662297SShilei Tian     auto &CallerKernelInfoAA = A.getAAFor<AAKernelInfo>(
4247ca662297SShilei Tian         *this, IRPosition::function(*getAnchorScope()), DepClassTy::REQUIRED);
4248ca662297SShilei Tian 
4249ca662297SShilei Tian     if (!CallerKernelInfoAA.ReachingKernelEntries.isValidState())
4250ca662297SShilei Tian       return indicatePessimisticFixpoint();
4251ca662297SShilei Tian 
4252ca662297SShilei Tian     for (Kernel K : CallerKernelInfoAA.ReachingKernelEntries) {
4253ca662297SShilei Tian       auto &AA = A.getAAFor<AAKernelInfo>(*this, IRPosition::function(*K),
4254ca662297SShilei Tian                                           DepClassTy::REQUIRED);
4255ca662297SShilei Tian 
4256ca662297SShilei Tian       if (!AA.isValidState()) {
4257ca662297SShilei Tian         SimplifiedValue = nullptr;
4258ca662297SShilei Tian         return indicatePessimisticFixpoint();
4259ca662297SShilei Tian       }
4260ca662297SShilei Tian 
4261ca662297SShilei Tian       if (AA.SPMDCompatibilityTracker.isAssumed()) {
4262ca662297SShilei Tian         if (AA.SPMDCompatibilityTracker.isAtFixpoint())
4263ca662297SShilei Tian           ++KnownSPMDCount;
4264ca662297SShilei Tian         else
4265ca662297SShilei Tian           ++AssumedSPMDCount;
4266ca662297SShilei Tian       } else {
4267ca662297SShilei Tian         if (AA.SPMDCompatibilityTracker.isAtFixpoint())
4268ca662297SShilei Tian           ++KnownNonSPMDCount;
4269ca662297SShilei Tian         else
4270ca662297SShilei Tian           ++AssumedNonSPMDCount;
4271ca662297SShilei Tian       }
4272ca662297SShilei Tian     }
4273ca662297SShilei Tian 
4274ae69f468SShilei Tian     if ((AssumedSPMDCount + KnownSPMDCount) &&
4275ae69f468SShilei Tian         (AssumedNonSPMDCount + KnownNonSPMDCount))
4276ca662297SShilei Tian       return indicatePessimisticFixpoint();
4277ca662297SShilei Tian 
4278ca662297SShilei Tian     auto &Ctx = getAnchorValue().getContext();
4279ca662297SShilei Tian     if (KnownSPMDCount || AssumedSPMDCount) {
4280ca662297SShilei Tian       assert(KnownNonSPMDCount == 0 && AssumedNonSPMDCount == 0 &&
4281ca662297SShilei Tian              "Expected only SPMD kernels!");
4282ca662297SShilei Tian       // All reaching kernels are in SPMD mode. Update all function calls to
4283ca662297SShilei Tian       // __kmpc_is_spmd_exec_mode to 1.
4284ca662297SShilei Tian       SimplifiedValue = ConstantInt::get(Type::getInt8Ty(Ctx), true);
4285d3454ee8SShilei Tian     } else if (KnownNonSPMDCount || AssumedNonSPMDCount) {
4286ca662297SShilei Tian       assert(KnownSPMDCount == 0 && AssumedSPMDCount == 0 &&
4287ca662297SShilei Tian              "Expected only non-SPMD kernels!");
4288ca662297SShilei Tian       // All reaching kernels are in non-SPMD mode. Update all function
4289ca662297SShilei Tian       // calls to __kmpc_is_spmd_exec_mode to 0.
4290ca662297SShilei Tian       SimplifiedValue = ConstantInt::get(Type::getInt8Ty(Ctx), false);
4291d3454ee8SShilei Tian     } else {
4292d3454ee8SShilei Tian       // We have empty reaching kernels, therefore we cannot tell if the
4293d3454ee8SShilei Tian       // associated call site can be folded. At this moment, SimplifiedValue
4294d3454ee8SShilei Tian       // must be none.
4295d3454ee8SShilei Tian       assert(!SimplifiedValue.hasValue() && "SimplifiedValue should be none");
4296ca662297SShilei Tian     }
4297ca662297SShilei Tian 
4298ca662297SShilei Tian     return SimplifiedValue == SimplifiedValueBefore ? ChangeStatus::UNCHANGED
4299ca662297SShilei Tian                                                     : ChangeStatus::CHANGED;
4300ca662297SShilei Tian   }
4301ca662297SShilei Tian 
4302196fe994SJoseph Huber   /// Fold __kmpc_is_generic_main_thread_id into a constant if possible.
4303196fe994SJoseph Huber   ChangeStatus foldIsGenericMainThread(Attributor &A) {
4304196fe994SJoseph Huber     Optional<Value *> SimplifiedValueBefore = SimplifiedValue;
4305196fe994SJoseph Huber 
4306196fe994SJoseph Huber     CallBase &CB = cast<CallBase>(getAssociatedValue());
4307196fe994SJoseph Huber     Function *F = CB.getFunction();
4308196fe994SJoseph Huber     const auto &ExecutionDomainAA = A.getAAFor<AAExecutionDomain>(
4309196fe994SJoseph Huber         *this, IRPosition::function(*F), DepClassTy::REQUIRED);
4310196fe994SJoseph Huber 
4311196fe994SJoseph Huber     if (!ExecutionDomainAA.isValidState())
4312196fe994SJoseph Huber       return indicatePessimisticFixpoint();
4313196fe994SJoseph Huber 
4314196fe994SJoseph Huber     auto &Ctx = getAnchorValue().getContext();
4315196fe994SJoseph Huber     if (ExecutionDomainAA.isExecutedByInitialThreadOnly(CB))
4316196fe994SJoseph Huber       SimplifiedValue = ConstantInt::get(Type::getInt8Ty(Ctx), true);
4317196fe994SJoseph Huber     else
4318196fe994SJoseph Huber       return indicatePessimisticFixpoint();
4319196fe994SJoseph Huber 
4320196fe994SJoseph Huber     return SimplifiedValue == SimplifiedValueBefore ? ChangeStatus::UNCHANGED
4321196fe994SJoseph Huber                                                     : ChangeStatus::CHANGED;
4322196fe994SJoseph Huber   }
4323196fe994SJoseph Huber 
4324e97e0a4fSShilei Tian   /// Fold __kmpc_parallel_level into a constant if possible.
4325e97e0a4fSShilei Tian   ChangeStatus foldParallelLevel(Attributor &A) {
4326e97e0a4fSShilei Tian     Optional<Value *> SimplifiedValueBefore = SimplifiedValue;
4327e97e0a4fSShilei Tian 
4328e97e0a4fSShilei Tian     auto &CallerKernelInfoAA = A.getAAFor<AAKernelInfo>(
4329e97e0a4fSShilei Tian         *this, IRPosition::function(*getAnchorScope()), DepClassTy::REQUIRED);
4330e97e0a4fSShilei Tian 
4331e97e0a4fSShilei Tian     if (!CallerKernelInfoAA.ParallelLevels.isValidState())
4332e97e0a4fSShilei Tian       return indicatePessimisticFixpoint();
4333e97e0a4fSShilei Tian 
4334e97e0a4fSShilei Tian     if (!CallerKernelInfoAA.ReachingKernelEntries.isValidState())
4335e97e0a4fSShilei Tian       return indicatePessimisticFixpoint();
4336e97e0a4fSShilei Tian 
4337e97e0a4fSShilei Tian     if (CallerKernelInfoAA.ReachingKernelEntries.empty()) {
4338e97e0a4fSShilei Tian       assert(!SimplifiedValue.hasValue() &&
4339e97e0a4fSShilei Tian              "SimplifiedValue should keep none at this point");
4340e97e0a4fSShilei Tian       return ChangeStatus::UNCHANGED;
4341e97e0a4fSShilei Tian     }
4342e97e0a4fSShilei Tian 
4343e97e0a4fSShilei Tian     unsigned AssumedSPMDCount = 0, KnownSPMDCount = 0;
4344e97e0a4fSShilei Tian     unsigned AssumedNonSPMDCount = 0, KnownNonSPMDCount = 0;
4345e97e0a4fSShilei Tian     for (Kernel K : CallerKernelInfoAA.ReachingKernelEntries) {
4346e97e0a4fSShilei Tian       auto &AA = A.getAAFor<AAKernelInfo>(*this, IRPosition::function(*K),
4347e97e0a4fSShilei Tian                                           DepClassTy::REQUIRED);
4348e97e0a4fSShilei Tian       if (!AA.SPMDCompatibilityTracker.isValidState())
4349e97e0a4fSShilei Tian         return indicatePessimisticFixpoint();
4350e97e0a4fSShilei Tian 
4351e97e0a4fSShilei Tian       if (AA.SPMDCompatibilityTracker.isAssumed()) {
4352e97e0a4fSShilei Tian         if (AA.SPMDCompatibilityTracker.isAtFixpoint())
4353e97e0a4fSShilei Tian           ++KnownSPMDCount;
4354e97e0a4fSShilei Tian         else
4355e97e0a4fSShilei Tian           ++AssumedSPMDCount;
4356e97e0a4fSShilei Tian       } else {
4357e97e0a4fSShilei Tian         if (AA.SPMDCompatibilityTracker.isAtFixpoint())
4358e97e0a4fSShilei Tian           ++KnownNonSPMDCount;
4359e97e0a4fSShilei Tian         else
4360e97e0a4fSShilei Tian           ++AssumedNonSPMDCount;
4361e97e0a4fSShilei Tian       }
4362e97e0a4fSShilei Tian     }
4363e97e0a4fSShilei Tian 
4364e97e0a4fSShilei Tian     if ((AssumedSPMDCount + KnownSPMDCount) &&
4365e97e0a4fSShilei Tian         (AssumedNonSPMDCount + KnownNonSPMDCount))
4366e97e0a4fSShilei Tian       return indicatePessimisticFixpoint();
4367e97e0a4fSShilei Tian 
4368e97e0a4fSShilei Tian     auto &Ctx = getAnchorValue().getContext();
4369e97e0a4fSShilei Tian     // If the caller can only be reached by SPMD kernel entries, the parallel
4370e97e0a4fSShilei Tian     // level is 1. Similarly, if the caller can only be reached by non-SPMD
4371e97e0a4fSShilei Tian     // kernel entries, it is 0.
4372e97e0a4fSShilei Tian     if (AssumedSPMDCount || KnownSPMDCount) {
4373e97e0a4fSShilei Tian       assert(KnownNonSPMDCount == 0 && AssumedNonSPMDCount == 0 &&
4374e97e0a4fSShilei Tian              "Expected only SPMD kernels!");
4375e97e0a4fSShilei Tian       SimplifiedValue = ConstantInt::get(Type::getInt8Ty(Ctx), 1);
4376e97e0a4fSShilei Tian     } else {
4377e97e0a4fSShilei Tian       assert(KnownSPMDCount == 0 && AssumedSPMDCount == 0 &&
4378e97e0a4fSShilei Tian              "Expected only non-SPMD kernels!");
4379e97e0a4fSShilei Tian       SimplifiedValue = ConstantInt::get(Type::getInt8Ty(Ctx), 0);
4380e97e0a4fSShilei Tian     }
43815ab6aeddSJose M Monsalve Diaz     return SimplifiedValue == SimplifiedValueBefore ? ChangeStatus::UNCHANGED
43825ab6aeddSJose M Monsalve Diaz                                                     : ChangeStatus::CHANGED;
43835ab6aeddSJose M Monsalve Diaz   }
4384e97e0a4fSShilei Tian 
43855ab6aeddSJose M Monsalve Diaz   ChangeStatus foldKernelFnAttribute(Attributor &A, llvm::StringRef Attr) {
43865ab6aeddSJose M Monsalve Diaz     // Specialize only if all the calls agree with the attribute constant value
43875ab6aeddSJose M Monsalve Diaz     int32_t CurrentAttrValue = -1;
43885ab6aeddSJose M Monsalve Diaz     Optional<Value *> SimplifiedValueBefore = SimplifiedValue;
43895ab6aeddSJose M Monsalve Diaz 
43905ab6aeddSJose M Monsalve Diaz     auto &CallerKernelInfoAA = A.getAAFor<AAKernelInfo>(
43915ab6aeddSJose M Monsalve Diaz         *this, IRPosition::function(*getAnchorScope()), DepClassTy::REQUIRED);
43925ab6aeddSJose M Monsalve Diaz 
43935ab6aeddSJose M Monsalve Diaz     if (!CallerKernelInfoAA.ReachingKernelEntries.isValidState())
43945ab6aeddSJose M Monsalve Diaz       return indicatePessimisticFixpoint();
43955ab6aeddSJose M Monsalve Diaz 
43965ab6aeddSJose M Monsalve Diaz     // Iterate over the kernels that reach this function
43975ab6aeddSJose M Monsalve Diaz     for (Kernel K : CallerKernelInfoAA.ReachingKernelEntries) {
43985ab6aeddSJose M Monsalve Diaz       int32_t NextAttrVal = -1;
43995ab6aeddSJose M Monsalve Diaz       if (K->hasFnAttribute(Attr))
44005ab6aeddSJose M Monsalve Diaz         NextAttrVal =
44015ab6aeddSJose M Monsalve Diaz             std::stoi(K->getFnAttribute(Attr).getValueAsString().str());
44025ab6aeddSJose M Monsalve Diaz 
44035ab6aeddSJose M Monsalve Diaz       if (NextAttrVal == -1 ||
44045ab6aeddSJose M Monsalve Diaz           (CurrentAttrValue != -1 && CurrentAttrValue != NextAttrVal))
44055ab6aeddSJose M Monsalve Diaz         return indicatePessimisticFixpoint();
44065ab6aeddSJose M Monsalve Diaz       CurrentAttrValue = NextAttrVal;
44075ab6aeddSJose M Monsalve Diaz     }
44085ab6aeddSJose M Monsalve Diaz 
44095ab6aeddSJose M Monsalve Diaz     if (CurrentAttrValue != -1) {
44105ab6aeddSJose M Monsalve Diaz       auto &Ctx = getAnchorValue().getContext();
44115ab6aeddSJose M Monsalve Diaz       SimplifiedValue =
44125ab6aeddSJose M Monsalve Diaz           ConstantInt::get(Type::getInt32Ty(Ctx), CurrentAttrValue);
44135ab6aeddSJose M Monsalve Diaz     }
4414e97e0a4fSShilei Tian     return SimplifiedValue == SimplifiedValueBefore ? ChangeStatus::UNCHANGED
4415e97e0a4fSShilei Tian                                                     : ChangeStatus::CHANGED;
4416e97e0a4fSShilei Tian   }
4417e97e0a4fSShilei Tian 
4418ca662297SShilei Tian   /// An optional value the associated value is assumed to fold to. That is, we
4419ca662297SShilei Tian   /// assume the associated value (which is a call) can be replaced by this
4420ca662297SShilei Tian   /// simplified value.
4421ca662297SShilei Tian   Optional<Value *> SimplifiedValue;
4422ca662297SShilei Tian 
4423ca662297SShilei Tian   /// The runtime function kind of the callee of the associated call site.
4424ca662297SShilei Tian   RuntimeFunction RFKind;
4425ca662297SShilei Tian };
4426ca662297SShilei Tian 
44279548b74aSJohannes Doerfert } // namespace
44289548b74aSJohannes Doerfert 
44295ab6aeddSJose M Monsalve Diaz /// Register folding callsite
44305ab6aeddSJose M Monsalve Diaz void OpenMPOpt::registerFoldRuntimeCall(RuntimeFunction RF) {
44315ab6aeddSJose M Monsalve Diaz   auto &RFI = OMPInfoCache.RFIs[RF];
44325ab6aeddSJose M Monsalve Diaz   RFI.foreachUse(SCC, [&](Use &U, Function &F) {
44335ab6aeddSJose M Monsalve Diaz     CallInst *CI = OpenMPOpt::getCallIfRegularCall(U, &RFI);
44345ab6aeddSJose M Monsalve Diaz     if (!CI)
44355ab6aeddSJose M Monsalve Diaz       return false;
44365ab6aeddSJose M Monsalve Diaz     A.getOrCreateAAFor<AAFoldRuntimeCall>(
44375ab6aeddSJose M Monsalve Diaz         IRPosition::callsite_returned(*CI), /* QueryingAA */ nullptr,
44385ab6aeddSJose M Monsalve Diaz         DepClassTy::NONE, /* ForceUpdate */ false,
44395ab6aeddSJose M Monsalve Diaz         /* UpdateAfterInit */ false);
44405ab6aeddSJose M Monsalve Diaz     return false;
44415ab6aeddSJose M Monsalve Diaz   });
44425ab6aeddSJose M Monsalve Diaz }
44435ab6aeddSJose M Monsalve Diaz 
4444d9659bf6SJohannes Doerfert void OpenMPOpt::registerAAs(bool IsModulePass) {
4445d9659bf6SJohannes Doerfert   if (SCC.empty())
4446d9659bf6SJohannes Doerfert 
4447d9659bf6SJohannes Doerfert     return;
4448d9659bf6SJohannes Doerfert   if (IsModulePass) {
4449d9659bf6SJohannes Doerfert     // Ensure we create the AAKernelInfo AAs first and without triggering an
4450d9659bf6SJohannes Doerfert     // update. This will make sure we register all value simplification
4451d9659bf6SJohannes Doerfert     // callbacks before any other AA has the chance to create an AAValueSimplify
4452d9659bf6SJohannes Doerfert     // or similar.
4453d9659bf6SJohannes Doerfert     for (Function *Kernel : OMPInfoCache.Kernels)
4454d9659bf6SJohannes Doerfert       A.getOrCreateAAFor<AAKernelInfo>(
4455d9659bf6SJohannes Doerfert           IRPosition::function(*Kernel), /* QueryingAA */ nullptr,
4456d9659bf6SJohannes Doerfert           DepClassTy::NONE, /* ForceUpdate */ false,
4457d9659bf6SJohannes Doerfert           /* UpdateAfterInit */ false);
4458ca662297SShilei Tian 
44595ab6aeddSJose M Monsalve Diaz     registerFoldRuntimeCall(OMPRTL___kmpc_is_generic_main_thread_id);
44605ab6aeddSJose M Monsalve Diaz     registerFoldRuntimeCall(OMPRTL___kmpc_is_spmd_exec_mode);
44615ab6aeddSJose M Monsalve Diaz     registerFoldRuntimeCall(OMPRTL___kmpc_parallel_level);
44625ab6aeddSJose M Monsalve Diaz     registerFoldRuntimeCall(OMPRTL___kmpc_get_hardware_num_threads_in_block);
44635ab6aeddSJose M Monsalve Diaz     registerFoldRuntimeCall(OMPRTL___kmpc_get_hardware_num_blocks);
4464d9659bf6SJohannes Doerfert   }
4465d9659bf6SJohannes Doerfert 
4466d9659bf6SJohannes Doerfert   // Create CallSite AA for all Getters.
4467d9659bf6SJohannes Doerfert   for (int Idx = 0; Idx < OMPInfoCache.ICVs.size() - 1; ++Idx) {
4468d9659bf6SJohannes Doerfert     auto ICVInfo = OMPInfoCache.ICVs[static_cast<InternalControlVar>(Idx)];
4469d9659bf6SJohannes Doerfert 
4470d9659bf6SJohannes Doerfert     auto &GetterRFI = OMPInfoCache.RFIs[ICVInfo.Getter];
4471d9659bf6SJohannes Doerfert 
4472d9659bf6SJohannes Doerfert     auto CreateAA = [&](Use &U, Function &Caller) {
4473d9659bf6SJohannes Doerfert       CallInst *CI = OpenMPOpt::getCallIfRegularCall(U, &GetterRFI);
4474d9659bf6SJohannes Doerfert       if (!CI)
4475d9659bf6SJohannes Doerfert         return false;
4476d9659bf6SJohannes Doerfert 
4477d9659bf6SJohannes Doerfert       auto &CB = cast<CallBase>(*CI);
4478d9659bf6SJohannes Doerfert 
4479d9659bf6SJohannes Doerfert       IRPosition CBPos = IRPosition::callsite_function(CB);
4480d9659bf6SJohannes Doerfert       A.getOrCreateAAFor<AAICVTracker>(CBPos);
4481d9659bf6SJohannes Doerfert       return false;
4482d9659bf6SJohannes Doerfert     };
4483d9659bf6SJohannes Doerfert 
4484d9659bf6SJohannes Doerfert     GetterRFI.foreachUse(SCC, CreateAA);
4485d9659bf6SJohannes Doerfert   }
4486d9659bf6SJohannes Doerfert   auto &GlobalizationRFI = OMPInfoCache.RFIs[OMPRTL___kmpc_alloc_shared];
4487d9659bf6SJohannes Doerfert   auto CreateAA = [&](Use &U, Function &F) {
4488d9659bf6SJohannes Doerfert     A.getOrCreateAAFor<AAHeapToShared>(IRPosition::function(F));
4489d9659bf6SJohannes Doerfert     return false;
4490d9659bf6SJohannes Doerfert   };
4491cd0dd8ecSJoseph Huber   if (!DisableOpenMPOptDeglobalization)
4492d9659bf6SJohannes Doerfert     GlobalizationRFI.foreachUse(SCC, CreateAA);
4493d9659bf6SJohannes Doerfert 
4494d9659bf6SJohannes Doerfert   // Create an ExecutionDomain AA for every function and a HeapToStack AA for
4495d9659bf6SJohannes Doerfert   // every function if there is a device kernel.
449670b75f62SJohannes Doerfert   if (!isOpenMPDevice(M))
449770b75f62SJohannes Doerfert     return;
449870b75f62SJohannes Doerfert 
4499d9659bf6SJohannes Doerfert   for (auto *F : SCC) {
450070b75f62SJohannes Doerfert     if (F->isDeclaration())
450170b75f62SJohannes Doerfert       continue;
450270b75f62SJohannes Doerfert 
4503d9659bf6SJohannes Doerfert     A.getOrCreateAAFor<AAExecutionDomain>(IRPosition::function(*F));
4504cd0dd8ecSJoseph Huber     if (!DisableOpenMPOptDeglobalization)
4505d9659bf6SJohannes Doerfert       A.getOrCreateAAFor<AAHeapToStack>(IRPosition::function(*F));
450670b75f62SJohannes Doerfert 
450770b75f62SJohannes Doerfert     for (auto &I : instructions(*F)) {
450870b75f62SJohannes Doerfert       if (auto *LI = dyn_cast<LoadInst>(&I)) {
450970b75f62SJohannes Doerfert         bool UsedAssumedInformation = false;
451070b75f62SJohannes Doerfert         A.getAssumedSimplified(IRPosition::value(*LI), /* AA */ nullptr,
451170b75f62SJohannes Doerfert                                UsedAssumedInformation);
45123e0c512cSJohannes Doerfert       } else if (auto *SI = dyn_cast<StoreInst>(&I)) {
45133e0c512cSJohannes Doerfert         A.getOrCreateAAFor<AAIsDead>(IRPosition::value(*SI));
451470b75f62SJohannes Doerfert       }
451570b75f62SJohannes Doerfert     }
4516d9659bf6SJohannes Doerfert   }
4517d9659bf6SJohannes Doerfert }
4518d9659bf6SJohannes Doerfert 
4519b8235d2bSsstefan1 const char AAICVTracker::ID = 0;
4520d9659bf6SJohannes Doerfert const char AAKernelInfo::ID = 0;
452118283125SJoseph Huber const char AAExecutionDomain::ID = 0;
45226fc51c9fSJoseph Huber const char AAHeapToShared::ID = 0;
4523ca662297SShilei Tian const char AAFoldRuntimeCall::ID = 0;
4524b8235d2bSsstefan1 
4525b8235d2bSsstefan1 AAICVTracker &AAICVTracker::createForPosition(const IRPosition &IRP,
4526b8235d2bSsstefan1                                               Attributor &A) {
4527b8235d2bSsstefan1   AAICVTracker *AA = nullptr;
4528b8235d2bSsstefan1   switch (IRP.getPositionKind()) {
4529b8235d2bSsstefan1   case IRPosition::IRP_INVALID:
4530b8235d2bSsstefan1   case IRPosition::IRP_FLOAT:
4531b8235d2bSsstefan1   case IRPosition::IRP_ARGUMENT:
4532b8235d2bSsstefan1   case IRPosition::IRP_CALL_SITE_ARGUMENT:
45331de70a72SJohannes Doerfert     llvm_unreachable("ICVTracker can only be created for function position!");
45345dfd7cc4Ssstefan1   case IRPosition::IRP_RETURNED:
45355dfd7cc4Ssstefan1     AA = new (A.Allocator) AAICVTrackerFunctionReturned(IRP, A);
45365dfd7cc4Ssstefan1     break;
45375dfd7cc4Ssstefan1   case IRPosition::IRP_CALL_SITE_RETURNED:
45385dfd7cc4Ssstefan1     AA = new (A.Allocator) AAICVTrackerCallSiteReturned(IRP, A);
45395dfd7cc4Ssstefan1     break;
45405dfd7cc4Ssstefan1   case IRPosition::IRP_CALL_SITE:
45415dfd7cc4Ssstefan1     AA = new (A.Allocator) AAICVTrackerCallSite(IRP, A);
45425dfd7cc4Ssstefan1     break;
4543b8235d2bSsstefan1   case IRPosition::IRP_FUNCTION:
4544b8235d2bSsstefan1     AA = new (A.Allocator) AAICVTrackerFunction(IRP, A);
4545b8235d2bSsstefan1     break;
4546b8235d2bSsstefan1   }
4547b8235d2bSsstefan1 
4548b8235d2bSsstefan1   return *AA;
4549b8235d2bSsstefan1 }
4550b8235d2bSsstefan1 
455118283125SJoseph Huber AAExecutionDomain &AAExecutionDomain::createForPosition(const IRPosition &IRP,
455218283125SJoseph Huber                                                         Attributor &A) {
455318283125SJoseph Huber   AAExecutionDomainFunction *AA = nullptr;
455418283125SJoseph Huber   switch (IRP.getPositionKind()) {
455518283125SJoseph Huber   case IRPosition::IRP_INVALID:
455618283125SJoseph Huber   case IRPosition::IRP_FLOAT:
455718283125SJoseph Huber   case IRPosition::IRP_ARGUMENT:
455818283125SJoseph Huber   case IRPosition::IRP_CALL_SITE_ARGUMENT:
455918283125SJoseph Huber   case IRPosition::IRP_RETURNED:
456018283125SJoseph Huber   case IRPosition::IRP_CALL_SITE_RETURNED:
456118283125SJoseph Huber   case IRPosition::IRP_CALL_SITE:
456218283125SJoseph Huber     llvm_unreachable(
456318283125SJoseph Huber         "AAExecutionDomain can only be created for function position!");
456418283125SJoseph Huber   case IRPosition::IRP_FUNCTION:
456518283125SJoseph Huber     AA = new (A.Allocator) AAExecutionDomainFunction(IRP, A);
456618283125SJoseph Huber     break;
456718283125SJoseph Huber   }
456818283125SJoseph Huber 
456918283125SJoseph Huber   return *AA;
457018283125SJoseph Huber }
457118283125SJoseph Huber 
45726fc51c9fSJoseph Huber AAHeapToShared &AAHeapToShared::createForPosition(const IRPosition &IRP,
45736fc51c9fSJoseph Huber                                                   Attributor &A) {
45746fc51c9fSJoseph Huber   AAHeapToSharedFunction *AA = nullptr;
45756fc51c9fSJoseph Huber   switch (IRP.getPositionKind()) {
45766fc51c9fSJoseph Huber   case IRPosition::IRP_INVALID:
45776fc51c9fSJoseph Huber   case IRPosition::IRP_FLOAT:
45786fc51c9fSJoseph Huber   case IRPosition::IRP_ARGUMENT:
45796fc51c9fSJoseph Huber   case IRPosition::IRP_CALL_SITE_ARGUMENT:
45806fc51c9fSJoseph Huber   case IRPosition::IRP_RETURNED:
45816fc51c9fSJoseph Huber   case IRPosition::IRP_CALL_SITE_RETURNED:
45826fc51c9fSJoseph Huber   case IRPosition::IRP_CALL_SITE:
45836fc51c9fSJoseph Huber     llvm_unreachable(
45846fc51c9fSJoseph Huber         "AAHeapToShared can only be created for function position!");
45856fc51c9fSJoseph Huber   case IRPosition::IRP_FUNCTION:
45866fc51c9fSJoseph Huber     AA = new (A.Allocator) AAHeapToSharedFunction(IRP, A);
45876fc51c9fSJoseph Huber     break;
45886fc51c9fSJoseph Huber   }
45896fc51c9fSJoseph Huber 
45906fc51c9fSJoseph Huber   return *AA;
45916fc51c9fSJoseph Huber }
45926fc51c9fSJoseph Huber 
4593d9659bf6SJohannes Doerfert AAKernelInfo &AAKernelInfo::createForPosition(const IRPosition &IRP,
4594d9659bf6SJohannes Doerfert                                               Attributor &A) {
4595d9659bf6SJohannes Doerfert   AAKernelInfo *AA = nullptr;
4596d9659bf6SJohannes Doerfert   switch (IRP.getPositionKind()) {
4597d9659bf6SJohannes Doerfert   case IRPosition::IRP_INVALID:
4598d9659bf6SJohannes Doerfert   case IRPosition::IRP_FLOAT:
4599d9659bf6SJohannes Doerfert   case IRPosition::IRP_ARGUMENT:
4600d9659bf6SJohannes Doerfert   case IRPosition::IRP_RETURNED:
4601d9659bf6SJohannes Doerfert   case IRPosition::IRP_CALL_SITE_RETURNED:
4602d9659bf6SJohannes Doerfert   case IRPosition::IRP_CALL_SITE_ARGUMENT:
4603d9659bf6SJohannes Doerfert     llvm_unreachable("KernelInfo can only be created for function position!");
4604d9659bf6SJohannes Doerfert   case IRPosition::IRP_CALL_SITE:
4605d9659bf6SJohannes Doerfert     AA = new (A.Allocator) AAKernelInfoCallSite(IRP, A);
4606d9659bf6SJohannes Doerfert     break;
4607d9659bf6SJohannes Doerfert   case IRPosition::IRP_FUNCTION:
4608d9659bf6SJohannes Doerfert     AA = new (A.Allocator) AAKernelInfoFunction(IRP, A);
4609d9659bf6SJohannes Doerfert     break;
4610d9659bf6SJohannes Doerfert   }
4611d9659bf6SJohannes Doerfert 
4612d9659bf6SJohannes Doerfert   return *AA;
4613d9659bf6SJohannes Doerfert }
4614d9659bf6SJohannes Doerfert 
4615ca662297SShilei Tian AAFoldRuntimeCall &AAFoldRuntimeCall::createForPosition(const IRPosition &IRP,
4616ca662297SShilei Tian                                                         Attributor &A) {
4617ca662297SShilei Tian   AAFoldRuntimeCall *AA = nullptr;
4618ca662297SShilei Tian   switch (IRP.getPositionKind()) {
4619ca662297SShilei Tian   case IRPosition::IRP_INVALID:
4620ca662297SShilei Tian   case IRPosition::IRP_FLOAT:
4621ca662297SShilei Tian   case IRPosition::IRP_ARGUMENT:
4622ca662297SShilei Tian   case IRPosition::IRP_RETURNED:
4623ca662297SShilei Tian   case IRPosition::IRP_FUNCTION:
4624ca662297SShilei Tian   case IRPosition::IRP_CALL_SITE:
4625ca662297SShilei Tian   case IRPosition::IRP_CALL_SITE_ARGUMENT:
4626ca662297SShilei Tian     llvm_unreachable("KernelInfo can only be created for call site position!");
4627ca662297SShilei Tian   case IRPosition::IRP_CALL_SITE_RETURNED:
4628ca662297SShilei Tian     AA = new (A.Allocator) AAFoldRuntimeCallCallSiteReturned(IRP, A);
4629ca662297SShilei Tian     break;
4630ca662297SShilei Tian   }
4631ca662297SShilei Tian 
4632ca662297SShilei Tian   return *AA;
4633ca662297SShilei Tian }
4634ca662297SShilei Tian 
4635b2ad63d3SJoseph Huber PreservedAnalyses OpenMPOptPass::run(Module &M, ModuleAnalysisManager &AM) {
46365ccb7424SJoseph Huber   if (!containsOpenMP(M))
4637b2ad63d3SJoseph Huber     return PreservedAnalyses::all();
4638b2ad63d3SJoseph Huber   if (DisableOpenMPOptimizations)
4639b2ad63d3SJoseph Huber     return PreservedAnalyses::all();
4640b2ad63d3SJoseph Huber 
46410edb8777SJoseph Huber   FunctionAnalysisManager &FAM =
46420edb8777SJoseph Huber       AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
46435ccb7424SJoseph Huber   KernelSet Kernels = getDeviceKernels(M);
46445ccb7424SJoseph Huber 
464557ad2e10SJoseph Huber   auto IsCalled = [&](Function &F) {
464657ad2e10SJoseph Huber     if (Kernels.contains(&F))
464757ad2e10SJoseph Huber       return true;
464857ad2e10SJoseph Huber     for (const User *U : F.users())
464957ad2e10SJoseph Huber       if (!isa<BlockAddress>(U))
465057ad2e10SJoseph Huber         return true;
465157ad2e10SJoseph Huber     return false;
465257ad2e10SJoseph Huber   };
465357ad2e10SJoseph Huber 
46540edb8777SJoseph Huber   auto EmitRemark = [&](Function &F) {
46550edb8777SJoseph Huber     auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);
46560edb8777SJoseph Huber     ORE.emit([&]() {
46572c31d5ebSJoseph Huber       OptimizationRemarkAnalysis ORA(DEBUG_TYPE, "OMP140", &F);
4658ecabc668SJoseph Huber       return ORA << "Could not internalize function. "
4659adbaa39dSJoseph Huber                  << "Some optimizations may not be possible. [OMP140]";
46600edb8777SJoseph Huber     });
46610edb8777SJoseph Huber   };
46620edb8777SJoseph Huber 
466357ad2e10SJoseph Huber   // Create internal copies of each function if this is a kernel Module. This
466457ad2e10SJoseph Huber   // allows iterprocedural passes to see every call edge.
4665adbaa39dSJoseph Huber   DenseMap<Function *, Function *> InternalizedMap;
4666adbaa39dSJoseph Huber   if (isOpenMPDevice(M)) {
4667adbaa39dSJoseph Huber     SmallPtrSet<Function *, 16> InternalizeFns;
466803d7e61cSJoseph Huber     for (Function &F : M)
46694a668604SJoseph Huber       if (!F.isDeclaration() && !Kernels.contains(&F) && IsCalled(F) &&
46704a668604SJoseph Huber           !DisableInternalization) {
4671adbaa39dSJoseph Huber         if (Attributor::isInternalizable(F)) {
4672adbaa39dSJoseph Huber           InternalizeFns.insert(&F);
4673ecabc668SJoseph Huber         } else if (!F.hasLocalLinkage() && !F.hasFnAttribute(Attribute::Cold)) {
46740edb8777SJoseph Huber           EmitRemark(F);
46750edb8777SJoseph Huber         }
46760edb8777SJoseph Huber       }
467703d7e61cSJoseph Huber 
4678adbaa39dSJoseph Huber     Attributor::internalizeFunctions(InternalizeFns, InternalizedMap);
4679adbaa39dSJoseph Huber   }
4680adbaa39dSJoseph Huber 
468157ad2e10SJoseph Huber   // Look at every function in the Module unless it was internalized.
4682b2ad63d3SJoseph Huber   SmallVector<Function *, 16> SCC;
468303d7e61cSJoseph Huber   for (Function &F : M)
4684adbaa39dSJoseph Huber     if (!F.isDeclaration() && !InternalizedMap.lookup(&F))
468503d7e61cSJoseph Huber       SCC.push_back(&F);
4686b2ad63d3SJoseph Huber 
4687b2ad63d3SJoseph Huber   if (SCC.empty())
4688b2ad63d3SJoseph Huber     return PreservedAnalyses::all();
4689b2ad63d3SJoseph Huber 
4690b2ad63d3SJoseph Huber   AnalysisGetter AG(FAM);
4691b2ad63d3SJoseph Huber 
4692b2ad63d3SJoseph Huber   auto OREGetter = [&FAM](Function *F) -> OptimizationRemarkEmitter & {
4693b2ad63d3SJoseph Huber     return FAM.getResult<OptimizationRemarkEmitterAnalysis>(*F);
4694b2ad63d3SJoseph Huber   };
4695b2ad63d3SJoseph Huber 
4696b2ad63d3SJoseph Huber   BumpPtrAllocator Allocator;
4697b2ad63d3SJoseph Huber   CallGraphUpdater CGUpdater;
4698b2ad63d3SJoseph Huber 
4699b2ad63d3SJoseph Huber   SetVector<Function *> Functions(SCC.begin(), SCC.end());
47005ccb7424SJoseph Huber   OMPInformationCache InfoCache(M, AG, Allocator, /*CGSCC*/ Functions, Kernels);
4701b2ad63d3SJoseph Huber 
4702f074a6a0SJoseph Huber   unsigned MaxFixpointIterations =
4703f074a6a0SJoseph Huber       (isOpenMPDevice(M)) ? SetFixpointIterations : 32;
47044a6bd8e3SJoseph Huber   Attributor A(Functions, InfoCache, CGUpdater, nullptr, true, false,
470513b2fba2SJoseph Huber                MaxFixpointIterations, OREGetter, DEBUG_TYPE);
4706b2ad63d3SJoseph Huber 
4707b2ad63d3SJoseph Huber   OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache, A);
4708b2ad63d3SJoseph Huber   bool Changed = OMPOpt.run(true);
4709339aa765SJoseph Huber 
471029a74a39SJoseph Huber   // Optionally inline device functions for potentially better performance.
471129a74a39SJoseph Huber   if (AlwaysInlineDeviceFunctions && isOpenMPDevice(M))
471229a74a39SJoseph Huber     for (Function &F : M)
471329a74a39SJoseph Huber       if (!F.isDeclaration() && !Kernels.contains(&F) &&
471429a74a39SJoseph Huber           !F.hasFnAttribute(Attribute::NoInline))
471529a74a39SJoseph Huber         F.addFnAttr(Attribute::AlwaysInline);
471629a74a39SJoseph Huber 
4717339aa765SJoseph Huber   if (PrintModuleAfterOptimizations)
4718339aa765SJoseph Huber     LLVM_DEBUG(dbgs() << TAG << "Module after OpenMPOpt Module Pass:\n" << M);
4719339aa765SJoseph Huber 
4720b2ad63d3SJoseph Huber   if (Changed)
4721b2ad63d3SJoseph Huber     return PreservedAnalyses::none();
4722b2ad63d3SJoseph Huber 
4723b2ad63d3SJoseph Huber   return PreservedAnalyses::all();
4724b2ad63d3SJoseph Huber }
4725b2ad63d3SJoseph Huber 
4726b2ad63d3SJoseph Huber PreservedAnalyses OpenMPOptCGSCCPass::run(LazyCallGraph::SCC &C,
47279548b74aSJohannes Doerfert                                           CGSCCAnalysisManager &AM,
4728b2ad63d3SJoseph Huber                                           LazyCallGraph &CG,
4729b2ad63d3SJoseph Huber                                           CGSCCUpdateResult &UR) {
47305ccb7424SJoseph Huber   if (!containsOpenMP(*C.begin()->getFunction().getParent()))
47319548b74aSJohannes Doerfert     return PreservedAnalyses::all();
47329548b74aSJohannes Doerfert   if (DisableOpenMPOptimizations)
47339548b74aSJohannes Doerfert     return PreservedAnalyses::all();
47349548b74aSJohannes Doerfert 
4735ee17263aSJohannes Doerfert   SmallVector<Function *, 16> SCC;
4736351d234dSRoman Lebedev   // If there are kernels in the module, we have to run on all SCC's.
4737351d234dSRoman Lebedev   for (LazyCallGraph::Node &N : C) {
4738351d234dSRoman Lebedev     Function *Fn = &N.getFunction();
4739351d234dSRoman Lebedev     SCC.push_back(Fn);
4740351d234dSRoman Lebedev   }
4741351d234dSRoman Lebedev 
47425ccb7424SJoseph Huber   if (SCC.empty())
47439548b74aSJohannes Doerfert     return PreservedAnalyses::all();
47449548b74aSJohannes Doerfert 
47455ccb7424SJoseph Huber   Module &M = *C.begin()->getFunction().getParent();
47465ccb7424SJoseph Huber 
47475ccb7424SJoseph Huber   KernelSet Kernels = getDeviceKernels(M);
47485ccb7424SJoseph Huber 
47494d4ea9acSHuber, Joseph   FunctionAnalysisManager &FAM =
47504d4ea9acSHuber, Joseph       AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
47517cfd267cSsstefan1 
47527cfd267cSsstefan1   AnalysisGetter AG(FAM);
47537cfd267cSsstefan1 
47547cfd267cSsstefan1   auto OREGetter = [&FAM](Function *F) -> OptimizationRemarkEmitter & {
47554d4ea9acSHuber, Joseph     return FAM.getResult<OptimizationRemarkEmitterAnalysis>(*F);
47564d4ea9acSHuber, Joseph   };
47574d4ea9acSHuber, Joseph 
4758b2ad63d3SJoseph Huber   BumpPtrAllocator Allocator;
47599548b74aSJohannes Doerfert   CallGraphUpdater CGUpdater;
47609548b74aSJohannes Doerfert   CGUpdater.initialize(CG, C, AM, UR);
47617cfd267cSsstefan1 
47627cfd267cSsstefan1   SetVector<Function *> Functions(SCC.begin(), SCC.end());
47637cfd267cSsstefan1   OMPInformationCache InfoCache(*(Functions.back()->getParent()), AG, Allocator,
47645ccb7424SJoseph Huber                                 /*CGSCC*/ Functions, Kernels);
47657cfd267cSsstefan1 
4766f074a6a0SJoseph Huber   unsigned MaxFixpointIterations =
4767f074a6a0SJoseph Huber       (isOpenMPDevice(M)) ? SetFixpointIterations : 32;
47684a6bd8e3SJoseph Huber   Attributor A(Functions, InfoCache, CGUpdater, nullptr, false, true,
476913b2fba2SJoseph Huber                MaxFixpointIterations, OREGetter, DEBUG_TYPE);
4770b8235d2bSsstefan1 
4771b8235d2bSsstefan1   OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache, A);
4772b2ad63d3SJoseph Huber   bool Changed = OMPOpt.run(false);
4773339aa765SJoseph Huber 
4774339aa765SJoseph Huber   if (PrintModuleAfterOptimizations)
4775339aa765SJoseph Huber     LLVM_DEBUG(dbgs() << TAG << "Module after OpenMPOpt CGSCC Pass:\n" << M);
4776339aa765SJoseph Huber 
4777694ded37SGiorgis Georgakoudis   if (Changed)
4778694ded37SGiorgis Georgakoudis     return PreservedAnalyses::none();
4779694ded37SGiorgis Georgakoudis 
47809548b74aSJohannes Doerfert   return PreservedAnalyses::all();
47819548b74aSJohannes Doerfert }
47828b57ed09SJoseph Huber 
47839548b74aSJohannes Doerfert namespace {
47849548b74aSJohannes Doerfert 
4785b2ad63d3SJoseph Huber struct OpenMPOptCGSCCLegacyPass : public CallGraphSCCPass {
47869548b74aSJohannes Doerfert   CallGraphUpdater CGUpdater;
47879548b74aSJohannes Doerfert   static char ID;
47889548b74aSJohannes Doerfert 
4789b2ad63d3SJoseph Huber   OpenMPOptCGSCCLegacyPass() : CallGraphSCCPass(ID) {
4790b2ad63d3SJoseph Huber     initializeOpenMPOptCGSCCLegacyPassPass(*PassRegistry::getPassRegistry());
47919548b74aSJohannes Doerfert   }
47929548b74aSJohannes Doerfert 
47939548b74aSJohannes Doerfert   void getAnalysisUsage(AnalysisUsage &AU) const override {
47949548b74aSJohannes Doerfert     CallGraphSCCPass::getAnalysisUsage(AU);
47959548b74aSJohannes Doerfert   }
47969548b74aSJohannes Doerfert 
47979548b74aSJohannes Doerfert   bool runOnSCC(CallGraphSCC &CGSCC) override {
47985ccb7424SJoseph Huber     if (!containsOpenMP(CGSCC.getCallGraph().getModule()))
47999548b74aSJohannes Doerfert       return false;
48009548b74aSJohannes Doerfert     if (DisableOpenMPOptimizations || skipSCC(CGSCC))
48019548b74aSJohannes Doerfert       return false;
48029548b74aSJohannes Doerfert 
4803ee17263aSJohannes Doerfert     SmallVector<Function *, 16> SCC;
4804351d234dSRoman Lebedev     // If there are kernels in the module, we have to run on all SCC's.
4805351d234dSRoman Lebedev     for (CallGraphNode *CGN : CGSCC) {
4806351d234dSRoman Lebedev       Function *Fn = CGN->getFunction();
4807351d234dSRoman Lebedev       if (!Fn || Fn->isDeclaration())
4808351d234dSRoman Lebedev         continue;
4809ee17263aSJohannes Doerfert       SCC.push_back(Fn);
4810351d234dSRoman Lebedev     }
4811351d234dSRoman Lebedev 
48125ccb7424SJoseph Huber     if (SCC.empty())
48139548b74aSJohannes Doerfert       return false;
48149548b74aSJohannes Doerfert 
48155ccb7424SJoseph Huber     Module &M = CGSCC.getCallGraph().getModule();
48165ccb7424SJoseph Huber     KernelSet Kernels = getDeviceKernels(M);
48175ccb7424SJoseph Huber 
48189548b74aSJohannes Doerfert     CallGraph &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph();
48199548b74aSJohannes Doerfert     CGUpdater.initialize(CG, CGSCC);
48209548b74aSJohannes Doerfert 
48214d4ea9acSHuber, Joseph     // Maintain a map of functions to avoid rebuilding the ORE
48224d4ea9acSHuber, Joseph     DenseMap<Function *, std::unique_ptr<OptimizationRemarkEmitter>> OREMap;
48234d4ea9acSHuber, Joseph     auto OREGetter = [&OREMap](Function *F) -> OptimizationRemarkEmitter & {
48244d4ea9acSHuber, Joseph       std::unique_ptr<OptimizationRemarkEmitter> &ORE = OREMap[F];
48254d4ea9acSHuber, Joseph       if (!ORE)
48264d4ea9acSHuber, Joseph         ORE = std::make_unique<OptimizationRemarkEmitter>(F);
48274d4ea9acSHuber, Joseph       return *ORE;
48284d4ea9acSHuber, Joseph     };
48294d4ea9acSHuber, Joseph 
48307cfd267cSsstefan1     AnalysisGetter AG;
48317cfd267cSsstefan1     SetVector<Function *> Functions(SCC.begin(), SCC.end());
48327cfd267cSsstefan1     BumpPtrAllocator Allocator;
48335ccb7424SJoseph Huber     OMPInformationCache InfoCache(*(Functions.back()->getParent()), AG,
48345ccb7424SJoseph Huber                                   Allocator,
48355ccb7424SJoseph Huber                                   /*CGSCC*/ Functions, Kernels);
48367cfd267cSsstefan1 
4837f074a6a0SJoseph Huber     unsigned MaxFixpointIterations =
4838f074a6a0SJoseph Huber         (isOpenMPDevice(M)) ? SetFixpointIterations : 32;
483930e36c9bSJoseph Huber     Attributor A(Functions, InfoCache, CGUpdater, nullptr, false, true,
484013b2fba2SJoseph Huber                  MaxFixpointIterations, OREGetter, DEBUG_TYPE);
4841b8235d2bSsstefan1 
4842b8235d2bSsstefan1     OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache, A);
4843339aa765SJoseph Huber     bool Result = OMPOpt.run(false);
4844339aa765SJoseph Huber 
4845339aa765SJoseph Huber     if (PrintModuleAfterOptimizations)
4846339aa765SJoseph Huber       LLVM_DEBUG(dbgs() << TAG << "Module after OpenMPOpt CGSCC Pass:\n" << M);
4847339aa765SJoseph Huber 
4848339aa765SJoseph Huber     return Result;
48499548b74aSJohannes Doerfert   }
48509548b74aSJohannes Doerfert 
48519548b74aSJohannes Doerfert   bool doFinalization(CallGraph &CG) override { return CGUpdater.finalize(); }
48529548b74aSJohannes Doerfert };
48539548b74aSJohannes Doerfert 
48549548b74aSJohannes Doerfert } // end anonymous namespace
48559548b74aSJohannes Doerfert 
48565ccb7424SJoseph Huber KernelSet llvm::omp::getDeviceKernels(Module &M) {
48575ccb7424SJoseph Huber   // TODO: Create a more cross-platform way of determining device kernels.
4858e8039ad4SJohannes Doerfert   NamedMDNode *MD = M.getOrInsertNamedMetadata("nvvm.annotations");
48595ccb7424SJoseph Huber   KernelSet Kernels;
48605ccb7424SJoseph Huber 
4861e8039ad4SJohannes Doerfert   if (!MD)
48625ccb7424SJoseph Huber     return Kernels;
4863e8039ad4SJohannes Doerfert 
4864e8039ad4SJohannes Doerfert   for (auto *Op : MD->operands()) {
4865e8039ad4SJohannes Doerfert     if (Op->getNumOperands() < 2)
4866e8039ad4SJohannes Doerfert       continue;
4867e8039ad4SJohannes Doerfert     MDString *KindID = dyn_cast<MDString>(Op->getOperand(1));
4868e8039ad4SJohannes Doerfert     if (!KindID || KindID->getString() != "kernel")
4869e8039ad4SJohannes Doerfert       continue;
4870e8039ad4SJohannes Doerfert 
4871e8039ad4SJohannes Doerfert     Function *KernelFn =
4872e8039ad4SJohannes Doerfert         mdconst::dyn_extract_or_null<Function>(Op->getOperand(0));
4873e8039ad4SJohannes Doerfert     if (!KernelFn)
4874e8039ad4SJohannes Doerfert       continue;
4875e8039ad4SJohannes Doerfert 
4876e8039ad4SJohannes Doerfert     ++NumOpenMPTargetRegionKernels;
4877e8039ad4SJohannes Doerfert 
4878e8039ad4SJohannes Doerfert     Kernels.insert(KernelFn);
4879e8039ad4SJohannes Doerfert   }
48805ccb7424SJoseph Huber 
48815ccb7424SJoseph Huber   return Kernels;
4882e8039ad4SJohannes Doerfert }
4883e8039ad4SJohannes Doerfert 
48845ccb7424SJoseph Huber bool llvm::omp::containsOpenMP(Module &M) {
48855ccb7424SJoseph Huber   Metadata *MD = M.getModuleFlag("openmp");
48865ccb7424SJoseph Huber   if (!MD)
48875ccb7424SJoseph Huber     return false;
4888dce6bc18SJohannes Doerfert 
4889e8039ad4SJohannes Doerfert   return true;
4890e8039ad4SJohannes Doerfert }
4891e8039ad4SJohannes Doerfert 
48925ccb7424SJoseph Huber bool llvm::omp::isOpenMPDevice(Module &M) {
48935ccb7424SJoseph Huber   Metadata *MD = M.getModuleFlag("openmp-device");
48945ccb7424SJoseph Huber   if (!MD)
48955ccb7424SJoseph Huber     return false;
48965ccb7424SJoseph Huber 
48975ccb7424SJoseph Huber   return true;
48989548b74aSJohannes Doerfert }
48999548b74aSJohannes Doerfert 
4900b2ad63d3SJoseph Huber char OpenMPOptCGSCCLegacyPass::ID = 0;
49019548b74aSJohannes Doerfert 
4902b2ad63d3SJoseph Huber INITIALIZE_PASS_BEGIN(OpenMPOptCGSCCLegacyPass, "openmp-opt-cgscc",
49039548b74aSJohannes Doerfert                       "OpenMP specific optimizations", false, false)
49049548b74aSJohannes Doerfert INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass)
4905b2ad63d3SJoseph Huber INITIALIZE_PASS_END(OpenMPOptCGSCCLegacyPass, "openmp-opt-cgscc",
49069548b74aSJohannes Doerfert                     "OpenMP specific optimizations", false, false)
49079548b74aSJohannes Doerfert 
4908b2ad63d3SJoseph Huber Pass *llvm::createOpenMPOptCGSCCLegacyPass() {
4909b2ad63d3SJoseph Huber   return new OpenMPOptCGSCCLegacyPass();
4910b2ad63d3SJoseph Huber }
4911