1 //===- IR/OpenMPIRBuilder.h - OpenMP encoding builder for LLVM IR - C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines the OpenMPIRBuilder class and helpers used as a convenient
10 // way to create LLVM instructions for OpenMP directives.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_OPENMP_IR_IRBUILDER_H
15 #define LLVM_OPENMP_IR_IRBUILDER_H
16 
17 #include "llvm/Frontend/OpenMP/OMPConstants.h"
18 #include "llvm/IR/DebugLoc.h"
19 #include "llvm/IR/IRBuilder.h"
20 #include "llvm/Support/Allocator.h"
21 
22 namespace llvm {
23 
24 /// An interface to create LLVM-IR for OpenMP directives.
25 ///
26 /// Each OpenMP directive has a corresponding public generator method.
27 class OpenMPIRBuilder {
28 public:
29   /// Create a new OpenMPIRBuilder operating on the given module \p M. This will
30   /// not have an effect on \p M (see initialize).
31   OpenMPIRBuilder(Module &M) : M(M), Builder(M.getContext()) {}
32 
33   /// Initialize the internal state, this will put structures types and
34   /// potentially other helpers into the underlying module. Must be called
35   /// before any other method and only once!
36   void initialize();
37 
38   /// Finalize the underlying module, e.g., by outlining regions.
39   void finalize();
40 
41   /// Add attributes known for \p FnID to \p Fn.
42   void addAttributes(omp::RuntimeFunction FnID, Function &Fn);
43 
44   /// Type used throughout for insertion points.
45   using InsertPointTy = IRBuilder<>::InsertPoint;
46 
47   /// Callback type for variable finalization (think destructors).
48   ///
49   /// \param CodeGenIP is the insertion point at which the finalization code
50   ///                  should be placed.
51   ///
52   /// A finalize callback knows about all objects that need finalization, e.g.
53   /// destruction, when the scope of the currently generated construct is left
54   /// at the time, and location, the callback is invoked.
55   using FinalizeCallbackTy = std::function<void(InsertPointTy CodeGenIP)>;
56 
57   struct FinalizationInfo {
58     /// The finalization callback provided by the last in-flight invocation of
59     /// CreateXXXX for the directive of kind DK.
60     FinalizeCallbackTy FiniCB;
61 
62     /// The directive kind of the innermost directive that has an associated
63     /// region which might require finalization when it is left.
64     omp::Directive DK;
65 
66     /// Flag to indicate if the directive is cancellable.
67     bool IsCancellable;
68   };
69 
70   /// Push a finalization callback on the finalization stack.
71   ///
72   /// NOTE: Temporary solution until Clang CG is gone.
73   void pushFinalizationCB(const FinalizationInfo &FI) {
74     FinalizationStack.push_back(FI);
75   }
76 
77   /// Pop the last finalization callback from the finalization stack.
78   ///
79   /// NOTE: Temporary solution until Clang CG is gone.
80   void popFinalizationCB() { FinalizationStack.pop_back(); }
81 
82   /// Callback type for body (=inner region) code generation
83   ///
84   /// The callback takes code locations as arguments, each describing a
85   /// location at which code might need to be generated or a location that is
86   /// the target of control transfer.
87   ///
88   /// \param AllocaIP is the insertion point at which new alloca instructions
89   ///                 should be placed.
90   /// \param CodeGenIP is the insertion point at which the body code should be
91   ///                  placed.
92   /// \param ContinuationBB is the basic block target to leave the body.
93   ///
94   /// Note that all blocks pointed to by the arguments have terminators.
95   using BodyGenCallbackTy =
96       function_ref<void(InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
97                         BasicBlock &ContinuationBB)>;
98 
99   /// Callback type for variable privatization (think copy & default
100   /// constructor).
101   ///
102   /// \param AllocaIP is the insertion point at which new alloca instructions
103   ///                 should be placed.
104   /// \param CodeGenIP is the insertion point at which the privatization code
105   ///                  should be placed.
106   /// \param Val The value beeing copied/created.
107   /// \param ReplVal The replacement value, thus a copy or new created version
108   ///                of \p Val.
109   ///
110   /// \returns The new insertion point where code generation continues and
111   ///          \p ReplVal the replacement of \p Val.
112   using PrivatizeCallbackTy = function_ref<InsertPointTy(
113       InsertPointTy AllocaIP, InsertPointTy CodeGenIP, Value &Val,
114       Value *&ReplVal)>;
115 
116   /// Description of a LLVM-IR insertion point (IP) and a debug/source location
117   /// (filename, line, column, ...).
118   struct LocationDescription {
119     template <typename T, typename U>
120     LocationDescription(const IRBuilder<T, U> &IRB)
121         : IP(IRB.saveIP()), DL(IRB.getCurrentDebugLocation()) {}
122     LocationDescription(const InsertPointTy &IP) : IP(IP) {}
123     LocationDescription(const InsertPointTy &IP, const DebugLoc &DL)
124         : IP(IP), DL(DL) {}
125     InsertPointTy IP;
126     DebugLoc DL;
127   };
128 
129   /// Emitter methods for OpenMP directives.
130   ///
131   ///{
132 
133   /// Generator for '#omp barrier'
134   ///
135   /// \param Loc The location where the barrier directive was encountered.
136   /// \param DK The kind of directive that caused the barrier.
137   /// \param ForceSimpleCall Flag to force a simple (=non-cancellation) barrier.
138   /// \param CheckCancelFlag Flag to indicate a cancel barrier return value
139   ///                        should be checked and acted upon.
140   ///
141   /// \returns The insertion point after the barrier.
142   InsertPointTy CreateBarrier(const LocationDescription &Loc, omp::Directive DK,
143                               bool ForceSimpleCall = false,
144                               bool CheckCancelFlag = true);
145 
146   /// Generator for '#omp cancel'
147   ///
148   /// \param Loc The location where the directive was encountered.
149   /// \param IfCondition The evaluated 'if' clause expression, if any.
150   /// \param CanceledDirective The kind of directive that is cancled.
151   ///
152   /// \returns The insertion point after the barrier.
153   InsertPointTy CreateCancel(const LocationDescription &Loc, Value *IfCondition,
154                              omp::Directive CanceledDirective);
155 
156   /// Generator for '#omp parallel'
157   ///
158   /// \param Loc The insert and source location description.
159   /// \param BodyGenCB Callback that will generate the region code.
160   /// \param PrivCB Callback to copy a given variable (think copy constructor).
161   /// \param FiniCB Callback to finalize variable copies.
162   /// \param IfCondition The evaluated 'if' clause expression, if any.
163   /// \param NumThreads The evaluated 'num_threads' clause expression, if any.
164   /// \param ProcBind The value of the 'proc_bind' clause (see ProcBindKind).
165   /// \param IsCancellable Flag to indicate a cancellable parallel region.
166   ///
167   /// \returns The insertion position *after* the parallel.
168   IRBuilder<>::InsertPoint
169   CreateParallel(const LocationDescription &Loc, BodyGenCallbackTy BodyGenCB,
170                  PrivatizeCallbackTy PrivCB, FinalizeCallbackTy FiniCB,
171                  Value *IfCondition, Value *NumThreads,
172                  omp::ProcBindKind ProcBind, bool IsCancellable);
173 
174   /// Generator for '#omp flush'
175   ///
176   /// \param Loc The location where the flush directive was encountered
177   void CreateFlush(const LocationDescription &Loc);
178 
179   /// Generator for '#omp taskwait'
180   ///
181   /// \param Loc The location where the taskwait directive was encountered.
182   void CreateTaskwait(const LocationDescription &Loc);
183 
184   /// Generator for '#omp taskyield'
185   ///
186   /// \param Loc The location where the taskyield directive was encountered.
187   void CreateTaskyield(const LocationDescription &Loc);
188 
189   ///}
190 
191   /// Return the insertion point used by the underlying IRBuilder.
192   InsertPointTy getInsertionPoint() { return Builder.saveIP(); }
193 
194   /// Update the internal location to \p Loc.
195   bool updateToLocation(const LocationDescription &Loc) {
196     Builder.restoreIP(Loc.IP);
197     Builder.SetCurrentDebugLocation(Loc.DL);
198     return Loc.IP.getBlock() != nullptr;
199   }
200 
201   /// Return the function declaration for the runtime function with \p FnID.
202   FunctionCallee getOrCreateRuntimeFunction(Module &M,
203                                             omp::RuntimeFunction FnID);
204 
205   Function *getOrCreateRuntimeFunctionPtr(omp::RuntimeFunction FnID);
206 
207   /// Return the (LLVM-IR) string describing the source location \p LocStr.
208   Constant *getOrCreateSrcLocStr(StringRef LocStr);
209 
210   /// Return the (LLVM-IR) string describing the default source location.
211   Constant *getOrCreateDefaultSrcLocStr();
212 
213   /// Return the (LLVM-IR) string describing the source location identified by
214   /// the arguments.
215   Constant *getOrCreateSrcLocStr(StringRef FunctionName, StringRef FileName,
216                                  unsigned Line, unsigned Column);
217 
218   /// Return the (LLVM-IR) string describing the source location \p Loc.
219   Constant *getOrCreateSrcLocStr(const LocationDescription &Loc);
220 
221   /// Return an ident_t* encoding the source location \p SrcLocStr and \p Flags.
222   /// TODO: Create a enum class for the Reserve2Flags
223   Value *getOrCreateIdent(Constant *SrcLocStr,
224                           omp::IdentFlag Flags = omp::IdentFlag(0),
225                           unsigned Reserve2Flags = 0);
226 
227   /// Generate control flow and cleanup for cancellation.
228   ///
229   /// \param CancelFlag Flag indicating if the cancellation is performed.
230   /// \param CanceledDirective The kind of directive that is cancled.
231   void emitCancelationCheckImpl(Value *CancelFlag,
232                                 omp::Directive CanceledDirective);
233 
234   /// Generate a barrier runtime call.
235   ///
236   /// \param Loc The location at which the request originated and is fulfilled.
237   /// \param DK The directive which caused the barrier
238   /// \param ForceSimpleCall Flag to force a simple (=non-cancellation) barrier.
239   /// \param CheckCancelFlag Flag to indicate a cancel barrier return value
240   ///                        should be checked and acted upon.
241   ///
242   /// \returns The insertion point after the barrier.
243   InsertPointTy emitBarrierImpl(const LocationDescription &Loc,
244                                 omp::Directive DK, bool ForceSimpleCall,
245                                 bool CheckCancelFlag);
246 
247   /// Generate a flush runtime call.
248   ///
249   /// \param Loc The location at which the request originated and is fulfilled.
250   void emitFlush(const LocationDescription &Loc);
251 
252   /// The finalization stack made up of finalize callbacks currently in-flight,
253   /// wrapped into FinalizationInfo objects that reference also the finalization
254   /// target block and the kind of cancellable directive.
255   SmallVector<FinalizationInfo, 8> FinalizationStack;
256 
257   /// Return true if the last entry in the finalization stack is of kind \p DK
258   /// and cancellable.
259   bool isLastFinalizationInfoCancellable(omp::Directive DK) {
260     return !FinalizationStack.empty() &&
261            FinalizationStack.back().IsCancellable &&
262            FinalizationStack.back().DK == DK;
263   }
264 
265   /// Generate a taskwait runtime call.
266   ///
267   /// \param Loc The location at which the request originated and is fulfilled.
268   void emitTaskwaitImpl(const LocationDescription &Loc);
269 
270   /// Generate a taskyield runtime call.
271   ///
272   /// \param Loc The location at which the request originated and is fulfilled.
273   void emitTaskyieldImpl(const LocationDescription &Loc);
274 
275   /// Return the current thread ID.
276   ///
277   /// \param Ident The ident (ident_t*) describing the query origin.
278   Value *getOrCreateThreadID(Value *Ident);
279 
280   /// The underlying LLVM-IR module
281   Module &M;
282 
283   /// The LLVM-IR Builder used to create IR.
284   IRBuilder<> Builder;
285 
286   /// Map to remember source location strings
287   StringMap<Constant *> SrcLocStrMap;
288 
289   /// Map to remember existing ident_t*.
290   DenseMap<std::pair<Constant *, uint64_t>, Value *> IdentMap;
291 
292   /// Helper that contains information about regions we need to outline
293   /// during finalization.
294   struct OutlineInfo {
295     using PostOutlineCBTy = std::function<void(Function &)>;
296     PostOutlineCBTy PostOutlineCB;
297     BasicBlock *EntryBB, *ExitBB;
298 
299     /// Collect all blocks in between EntryBB and ExitBB in both the given
300     /// vector and set.
301     void collectBlocks(SmallPtrSetImpl<BasicBlock *> &BlockSet,
302                        SmallVectorImpl<BasicBlock *> &BlockVector);
303   };
304 
305   /// Collection of regions that need to be outlined during finalization.
306   SmallVector<OutlineInfo, 16> OutlineInfos;
307 
308   /// Add a new region that will be outlined later.
309   void addOutlineInfo(OutlineInfo &&OI) { OutlineInfos.emplace_back(OI); }
310 
311   /// An ordered map of auto-generated variables to their unique names.
312   /// It stores variables with the following names: 1) ".gomp_critical_user_" +
313   /// <critical_section_name> + ".var" for "omp critical" directives; 2)
314   /// <mangled_name_for_global_var> + ".cache." for cache for threadprivate
315   /// variables.
316   StringMap<AssertingVH<Constant>, BumpPtrAllocator> InternalVars;
317 
318 public:
319   /// Generator for '#omp master'
320   ///
321   /// \param Loc The insert and source location description.
322   /// \param BodyGenCB Callback that will generate the region code.
323   /// \param FiniCB Callback to finalize variable copies.
324   ///
325   /// \returns The insertion position *after* the master.
326   InsertPointTy CreateMaster(const LocationDescription &Loc,
327                              BodyGenCallbackTy BodyGenCB,
328                              FinalizeCallbackTy FiniCB);
329 
330   /// Generator for '#omp critical'
331   ///
332   /// \param Loc The insert and source location description.
333   /// \param BodyGenCB Callback that will generate the region body code.
334   /// \param FiniCB Callback to finalize variable copies.
335   /// \param CriticalName name of the lock used by the critical directive
336   /// \param HintInst Hint Instruction for hint clause associated with critical
337   ///
338   /// \returns The insertion position *after* the master.
339   InsertPointTy CreateCritical(const LocationDescription &Loc,
340                                BodyGenCallbackTy BodyGenCB,
341                                FinalizeCallbackTy FiniCB,
342                                StringRef CriticalName, Value *HintInst);
343 
344   /// Generate conditional branch and relevant BasicBlocks through which private
345   /// threads copy the 'copyin' variables from Master copy to threadprivate
346   /// copies.
347   ///
348   /// \param IP insertion block for copyin conditional
349   /// \param MasterVarPtr a pointer to the master variable
350   /// \param PrivateVarPtr a pointer to the threadprivate variable
351   /// \param IntPtrTy Pointer size type
352   /// \param BranchtoEnd Create a branch between the copyin.not.master blocks
353   //				 and copy.in.end block
354   ///
355   /// \returns The insertion point where copying operation to be emitted.
356   InsertPointTy CreateCopyinClauseBlocks(InsertPointTy IP, Value *MasterAddr,
357                                          Value *PrivateAddr,
358                                          llvm::IntegerType *IntPtrTy,
359                                          bool BranchtoEnd = true);
360 
361   /// Create a runtime call for kmpc_Alloc
362   ///
363   /// \param Loc The insert and source location description.
364   /// \param Size Size of allocated memory space
365   /// \param Allocator Allocator information instruction
366   /// \param Name Name of call Instruction for OMP_alloc
367   ///
368   /// \returns CallInst to the OMP_Alloc call
369   CallInst *CreateOMPAlloc(const LocationDescription &Loc, Value *Size,
370                            Value *Allocator, std::string Name = "");
371 
372   /// Create a runtime call for kmpc_free
373   ///
374   /// \param Loc The insert and source location description.
375   /// \param Addr Address of memory space to be freed
376   /// \param Allocator Allocator information instruction
377   /// \param Name Name of call Instruction for OMP_Free
378   ///
379   /// \returns CallInst to the OMP_Free call
380   CallInst *CreateOMPFree(const LocationDescription &Loc, Value *Addr,
381                           Value *Allocator, std::string Name = "");
382 
383   /// Create a runtime call for kmpc_threadprivate_cached
384   ///
385   /// \param Loc The insert and source location description.
386   /// \param Pointer pointer to data to be cached
387   /// \param Size size of data to be cached
388   /// \param Name Name of call Instruction for callinst
389   ///
390   /// \returns CallInst to the thread private cache call.
391   CallInst *CreateCachedThreadPrivate(const LocationDescription &Loc,
392                                       llvm::Value *Pointer,
393                                       llvm::ConstantInt *Size,
394                                       const llvm::Twine &Name = Twine(""));
395 
396   /// Declarations for LLVM-IR types (simple, array, function and structure) are
397   /// generated below. Their names are defined and used in OpenMPKinds.def. Here
398   /// we provide the declarations, the initializeTypes function will provide the
399   /// values.
400   ///
401   ///{
402 #define OMP_TYPE(VarName, InitValue) Type *VarName = nullptr;
403 #define OMP_ARRAY_TYPE(VarName, ElemTy, ArraySize)                             \
404   ArrayType *VarName##Ty = nullptr;                                            \
405   PointerType *VarName##PtrTy = nullptr;
406 #define OMP_FUNCTION_TYPE(VarName, IsVarArg, ReturnType, ...)                  \
407   FunctionType *VarName = nullptr;                                             \
408   PointerType *VarName##Ptr = nullptr;
409 #define OMP_STRUCT_TYPE(VarName, StrName, ...)                                 \
410   StructType *VarName = nullptr;                                               \
411   PointerType *VarName##Ptr = nullptr;
412 #include "llvm/Frontend/OpenMP/OMPKinds.def"
413 
414   ///}
415 
416 private:
417   /// Create all simple and struct types exposed by the runtime and remember
418   /// the llvm::PointerTypes of them for easy access later.
419   void initializeTypes(Module &M);
420 
421   /// Common interface for generating entry calls for OMP Directives.
422   /// if the directive has a region/body, It will set the insertion
423   /// point to the body
424   ///
425   /// \param OMPD Directive to generate entry blocks for
426   /// \param EntryCall Call to the entry OMP Runtime Function
427   /// \param ExitBB block where the region ends.
428   /// \param Conditional indicate if the entry call result will be used
429   ///        to evaluate a conditional of whether a thread will execute
430   ///        body code or not.
431   ///
432   /// \return The insertion position in exit block
433   InsertPointTy emitCommonDirectiveEntry(omp::Directive OMPD, Value *EntryCall,
434                                          BasicBlock *ExitBB,
435                                          bool Conditional = false);
436 
437   /// Common interface to finalize the region
438   ///
439   /// \param OMPD Directive to generate exiting code for
440   /// \param FinIP Insertion point for emitting Finalization code and exit call
441   /// \param ExitCall Call to the ending OMP Runtime Function
442   /// \param HasFinalize indicate if the directive will require finalization
443   ///         and has a finalization callback in the stack that
444   ///        should be called.
445   ///
446   /// \return The insertion position in exit block
447   InsertPointTy emitCommonDirectiveExit(omp::Directive OMPD,
448                                         InsertPointTy FinIP,
449                                         Instruction *ExitCall,
450                                         bool HasFinalize = true);
451 
452   /// Common Interface to generate OMP inlined regions
453   ///
454   /// \param OMPD Directive to generate inlined region for
455   /// \param EntryCall Call to the entry OMP Runtime Function
456   /// \param ExitCall Call to the ending OMP Runtime Function
457   /// \param BodyGenCB Body code generation callback.
458   /// \param FiniCB Finalization Callback. Will be called when finalizing region
459   /// \param Conditional indicate if the entry call result will be used
460   ///        to evaluate a conditional of whether a thread will execute
461   ///        body code or not.
462   /// \param HasFinalize indicate if the directive will require finalization
463   ///         and has a finalization callback in the stack that
464   /// should        be called.
465   ///
466   /// \return The insertion point after the region
467 
468   InsertPointTy
469   EmitOMPInlinedRegion(omp::Directive OMPD, Instruction *EntryCall,
470                        Instruction *ExitCall, BodyGenCallbackTy BodyGenCB,
471                        FinalizeCallbackTy FiniCB, bool Conditional = false,
472                        bool HasFinalize = true);
473 
474   /// Get the platform-specific name separator.
475   /// \param Parts different parts of the final name that needs separation
476   /// \param FirstSeparator First separator used between the initial two
477   ///        parts of the name.
478   /// \param Separator separator used between all of the rest consecutive
479   ///        parts of the name
480   static std::string getNameWithSeparators(ArrayRef<StringRef> Parts,
481                                            StringRef FirstSeparator,
482                                            StringRef Separator);
483 
484   /// Gets (if variable with the given name already exist) or creates
485   /// internal global variable with the specified Name. The created variable has
486   /// linkage CommonLinkage by default and is initialized by null value.
487   /// \param Ty Type of the global variable. If it is exist already the type
488   /// must be the same.
489   /// \param Name Name of the variable.
490   Constant *getOrCreateOMPInternalVariable(Type *Ty, const Twine &Name,
491                                            unsigned AddressSpace = 0);
492 
493   /// Returns corresponding lock object for the specified critical region
494   /// name. If the lock object does not exist it is created, otherwise the
495   /// reference to the existing copy is returned.
496   /// \param CriticalName Name of the critical region.
497   ///
498   Value *getOMPCriticalRegionLock(StringRef CriticalName);
499 };
500 
501 } // end namespace llvm
502 
503 #endif // LLVM_IR_IRBUILDER_H
504