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