blob: 5706e7c75277cd295a8d42d7be4e44dc9a0f9a15 [file] [log] [blame]
Johannes Doerfertd23c6142019-11-05 18:57:44 -06001//===- OpenMPIRBuilder.cpp - Builder for LLVM-IR for OpenMP directives ----===//
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/// \file
9///
10/// This file implements the OpenMPIRBuilder class, which is used as a
11/// convenient way to create LLVM instructions for OpenMP directives.
12///
13//===----------------------------------------------------------------------===//
14
15#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
16
17#include "llvm/ADT/StringRef.h"
18#include "llvm/ADT/StringSwitch.h"
Johannes Doerferte4add9722019-12-25 16:59:38 -060019#include "llvm/IR/CFG.h"
Johannes Doerfertd23c6142019-11-05 18:57:44 -060020#include "llvm/IR/DebugInfo.h"
Kadir Cetinkaya5731b662020-02-10 14:44:51 +010021#include "llvm/IR/IRBuilder.h"
Fady Ghanim7438059a2020-02-15 00:42:23 -060022#include "llvm/IR/MDBuilder.h"
Johannes Doerfertd23c6142019-11-05 18:57:44 -060023#include "llvm/Support/CommandLine.h"
Johannes Doerferte4add9722019-12-25 16:59:38 -060024#include "llvm/Support/Error.h"
Johannes Doerfertd23c6142019-11-05 18:57:44 -060025#include "llvm/Transforms/Utils/BasicBlockUtils.h"
Johannes Doerferte4add9722019-12-25 16:59:38 -060026#include "llvm/Transforms/Utils/CodeExtractor.h"
Johannes Doerfertd23c6142019-11-05 18:57:44 -060027
28#include <sstream>
29
30#define DEBUG_TYPE "openmp-ir-builder"
31
32using namespace llvm;
33using namespace omp;
34using namespace types;
35
36static cl::opt<bool>
37 OptimisticAttributes("openmp-ir-builder-optimistic-attributes", cl::Hidden,
38 cl::desc("Use optimistic attributes describing "
39 "'as-if' properties of runtime calls."),
40 cl::init(false));
41
42void OpenMPIRBuilder::addAttributes(omp::RuntimeFunction FnID, Function &Fn) {
43 LLVMContext &Ctx = Fn.getContext();
44
45#define OMP_ATTRS_SET(VarName, AttrSet) AttributeSet VarName = AttrSet;
46#include "llvm/Frontend/OpenMP/OMPKinds.def"
47
48 // Add attributes to the new declaration.
49 switch (FnID) {
50#define OMP_RTL_ATTRS(Enum, FnAttrSet, RetAttrSet, ArgAttrSets) \
51 case Enum: \
52 Fn.setAttributes( \
53 AttributeList::get(Ctx, FnAttrSet, RetAttrSet, ArgAttrSets)); \
54 break;
55#include "llvm/Frontend/OpenMP/OMPKinds.def"
56 default:
57 // Attributes are optional.
58 break;
59 }
60}
61
62Function *OpenMPIRBuilder::getOrCreateRuntimeFunction(RuntimeFunction FnID) {
63 Function *Fn = nullptr;
64
65 // Try to find the declation in the module first.
66 switch (FnID) {
67#define OMP_RTL(Enum, Str, IsVarArg, ReturnType, ...) \
68 case Enum: \
69 Fn = M.getFunction(Str); \
70 break;
71#include "llvm/Frontend/OpenMP/OMPKinds.def"
72 }
73
74 if (!Fn) {
75 // Create a new declaration if we need one.
76 switch (FnID) {
77#define OMP_RTL(Enum, Str, IsVarArg, ReturnType, ...) \
78 case Enum: \
79 Fn = Function::Create(FunctionType::get(ReturnType, \
80 ArrayRef<Type *>{__VA_ARGS__}, \
81 IsVarArg), \
82 GlobalValue::ExternalLinkage, Str, M); \
83 break;
84#include "llvm/Frontend/OpenMP/OMPKinds.def"
85 }
86
87 addAttributes(FnID, *Fn);
88 }
89
90 assert(Fn && "Failed to create OpenMP runtime function");
91 return Fn;
92}
93
94void OpenMPIRBuilder::initialize() { initializeTypes(M); }
95
Johannes Doerfert70cac412020-02-12 20:52:23 -060096void OpenMPIRBuilder::finalize() {
97 for (OutlineInfo &OI : OutlineInfos) {
98 assert(!OI.Blocks.empty() &&
99 "Outlined regions should have at least a single block!");
100 BasicBlock *RegEntryBB = OI.Blocks.front();
101 Function *OuterFn = RegEntryBB->getParent();
102 CodeExtractorAnalysisCache CEAC(*OuterFn);
103 CodeExtractor Extractor(OI.Blocks, /* DominatorTree */ nullptr,
104 /* AggregateArgs */ false,
105 /* BlockFrequencyInfo */ nullptr,
106 /* BranchProbabilityInfo */ nullptr,
107 /* AssumptionCache */ nullptr,
108 /* AllowVarArgs */ true,
109 /* AllowAlloca */ true,
110 /* Suffix */ ".omp_par");
111
112 LLVM_DEBUG(dbgs() << "Before outlining: " << *OuterFn << "\n");
Johannes Doerfert3f3ec9c2020-02-13 00:39:55 -0600113 assert(Extractor.isEligible() &&
114 "Expected OpenMP outlining to be possible!");
Johannes Doerfert70cac412020-02-12 20:52:23 -0600115
116 Function *OutlinedFn = Extractor.extractCodeRegion(CEAC);
117
118 LLVM_DEBUG(dbgs() << "After outlining: " << *OuterFn << "\n");
119 LLVM_DEBUG(dbgs() << " Outlined function: " << *OutlinedFn << "\n");
120 assert(OutlinedFn->getReturnType()->isVoidTy() &&
121 "OpenMP outlined functions should not return a value!");
122
123 // For compability with the clang CG we move the outlined function after the
124 // one with the parallel region.
125 OutlinedFn->removeFromParent();
126 M.getFunctionList().insertAfter(OuterFn->getIterator(), OutlinedFn);
127
128 // Remove the artificial entry introduced by the extractor right away, we
129 // made our own entry block after all.
130 {
131 BasicBlock &ArtificialEntry = OutlinedFn->getEntryBlock();
132 assert(ArtificialEntry.getUniqueSuccessor() == RegEntryBB);
133 assert(RegEntryBB->getUniquePredecessor() == &ArtificialEntry);
134 RegEntryBB->moveBefore(&ArtificialEntry);
135 ArtificialEntry.eraseFromParent();
136 }
137 assert(&OutlinedFn->getEntryBlock() == RegEntryBB);
138 assert(OutlinedFn && OutlinedFn->getNumUses() == 1);
139
140 // Run a user callback, e.g. to add attributes.
141 if (OI.PostOutlineCB)
142 OI.PostOutlineCB(*OutlinedFn);
143 }
144
145 // Allow finalize to be called multiple times.
146 OutlineInfos.clear();
147}
148
Johannes Doerfertd23c6142019-11-05 18:57:44 -0600149Value *OpenMPIRBuilder::getOrCreateIdent(Constant *SrcLocStr,
150 IdentFlag LocFlags) {
151 // Enable "C-mode".
152 LocFlags |= OMP_IDENT_FLAG_KMPC;
153
154 GlobalVariable *&DefaultIdent = IdentMap[{SrcLocStr, uint64_t(LocFlags)}];
155 if (!DefaultIdent) {
156 Constant *I32Null = ConstantInt::getNullValue(Int32);
157 Constant *IdentData[] = {I32Null,
158 ConstantInt::get(Int32, uint64_t(LocFlags)),
159 I32Null, I32Null, SrcLocStr};
160 Constant *Initializer = ConstantStruct::get(
161 cast<StructType>(IdentPtr->getPointerElementType()), IdentData);
162
163 // Look for existing encoding of the location + flags, not needed but
164 // minimizes the difference to the existing solution while we transition.
165 for (GlobalVariable &GV : M.getGlobalList())
166 if (GV.getType() == IdentPtr && GV.hasInitializer())
167 if (GV.getInitializer() == Initializer)
168 return DefaultIdent = &GV;
169
170 DefaultIdent = new GlobalVariable(M, IdentPtr->getPointerElementType(),
171 /* isConstant = */ false,
172 GlobalValue::PrivateLinkage, Initializer);
173 DefaultIdent->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
174 DefaultIdent->setAlignment(Align(8));
175 }
176 return DefaultIdent;
177}
178
179Constant *OpenMPIRBuilder::getOrCreateSrcLocStr(StringRef LocStr) {
180 Constant *&SrcLocStr = SrcLocStrMap[LocStr];
181 if (!SrcLocStr) {
182 Constant *Initializer =
183 ConstantDataArray::getString(M.getContext(), LocStr);
184
185 // Look for existing encoding of the location, not needed but minimizes the
186 // difference to the existing solution while we transition.
187 for (GlobalVariable &GV : M.getGlobalList())
188 if (GV.isConstant() && GV.hasInitializer() &&
189 GV.getInitializer() == Initializer)
190 return SrcLocStr = ConstantExpr::getPointerCast(&GV, Int8Ptr);
191
192 SrcLocStr = Builder.CreateGlobalStringPtr(LocStr);
193 }
194 return SrcLocStr;
195}
196
197Constant *OpenMPIRBuilder::getOrCreateDefaultSrcLocStr() {
198 return getOrCreateSrcLocStr(";unknown;unknown;0;0;;");
199}
200
201Constant *
202OpenMPIRBuilder::getOrCreateSrcLocStr(const LocationDescription &Loc) {
203 DILocation *DIL = Loc.DL.get();
204 if (!DIL)
205 return getOrCreateDefaultSrcLocStr();
206 StringRef Filename =
207 !DIL->getFilename().empty() ? DIL->getFilename() : M.getName();
208 StringRef Function = DIL->getScope()->getSubprogram()->getName();
209 Function =
210 !Function.empty() ? Function : Loc.IP.getBlock()->getParent()->getName();
211 std::string LineStr = std::to_string(DIL->getLine());
212 std::string ColumnStr = std::to_string(DIL->getColumn());
213 std::stringstream SrcLocStr;
214 SrcLocStr << ";" << Filename.data() << ";" << Function.data() << ";"
215 << LineStr << ";" << ColumnStr << ";;";
216 return getOrCreateSrcLocStr(SrcLocStr.str());
217}
218
219Value *OpenMPIRBuilder::getOrCreateThreadID(Value *Ident) {
220 return Builder.CreateCall(
221 getOrCreateRuntimeFunction(OMPRTL___kmpc_global_thread_num), Ident,
222 "omp_global_thread_num");
223}
224
225OpenMPIRBuilder::InsertPointTy
226OpenMPIRBuilder::CreateBarrier(const LocationDescription &Loc, Directive DK,
227 bool ForceSimpleCall, bool CheckCancelFlag) {
228 if (!updateToLocation(Loc))
229 return Loc.IP;
230 return emitBarrierImpl(Loc, DK, ForceSimpleCall, CheckCancelFlag);
231}
232
233OpenMPIRBuilder::InsertPointTy
234OpenMPIRBuilder::emitBarrierImpl(const LocationDescription &Loc, Directive Kind,
235 bool ForceSimpleCall, bool CheckCancelFlag) {
236 // Build call __kmpc_cancel_barrier(loc, thread_id) or
237 // __kmpc_barrier(loc, thread_id);
238
239 IdentFlag BarrierLocFlags;
240 switch (Kind) {
241 case OMPD_for:
242 BarrierLocFlags = OMP_IDENT_FLAG_BARRIER_IMPL_FOR;
243 break;
244 case OMPD_sections:
245 BarrierLocFlags = OMP_IDENT_FLAG_BARRIER_IMPL_SECTIONS;
246 break;
247 case OMPD_single:
248 BarrierLocFlags = OMP_IDENT_FLAG_BARRIER_IMPL_SINGLE;
249 break;
250 case OMPD_barrier:
251 BarrierLocFlags = OMP_IDENT_FLAG_BARRIER_EXPL;
252 break;
253 default:
254 BarrierLocFlags = OMP_IDENT_FLAG_BARRIER_IMPL;
255 break;
256 }
257
258 Constant *SrcLocStr = getOrCreateSrcLocStr(Loc);
259 Value *Args[] = {getOrCreateIdent(SrcLocStr, BarrierLocFlags),
260 getOrCreateThreadID(getOrCreateIdent(SrcLocStr))};
261
262 // If we are in a cancellable parallel region, barriers are cancellation
263 // points.
264 // TODO: Check why we would force simple calls or to ignore the cancel flag.
Johannes Doerfertf9c3c5da2019-12-25 10:33:56 -0600265 bool UseCancelBarrier =
266 !ForceSimpleCall && isLastFinalizationInfoCancellable(OMPD_parallel);
Johannes Doerfertd23c6142019-11-05 18:57:44 -0600267
268 Value *Result = Builder.CreateCall(
269 getOrCreateRuntimeFunction(UseCancelBarrier ? OMPRTL___kmpc_cancel_barrier
270 : OMPRTL___kmpc_barrier),
271 Args);
272
Johannes Doerfert000c6a52019-12-27 15:53:37 -0600273 if (UseCancelBarrier && CheckCancelFlag)
274 emitCancelationCheckImpl(Result, OMPD_parallel);
Johannes Doerfertd23c6142019-11-05 18:57:44 -0600275
276 return Builder.saveIP();
277}
Johannes Doerferte4add9722019-12-25 16:59:38 -0600278
Johannes Doerfert000c6a52019-12-27 15:53:37 -0600279OpenMPIRBuilder::InsertPointTy
280OpenMPIRBuilder::CreateCancel(const LocationDescription &Loc,
281 Value *IfCondition,
282 omp::Directive CanceledDirective) {
283 if (!updateToLocation(Loc))
284 return Loc.IP;
285
286 // LLVM utilities like blocks with terminators.
287 auto *UI = Builder.CreateUnreachable();
288
289 Instruction *ThenTI = UI, *ElseTI = nullptr;
290 if (IfCondition)
291 SplitBlockAndInsertIfThenElse(IfCondition, UI, &ThenTI, &ElseTI);
292 Builder.SetInsertPoint(ThenTI);
293
294 Value *CancelKind = nullptr;
295 switch (CanceledDirective) {
296#define OMP_CANCEL_KIND(Enum, Str, DirectiveEnum, Value) \
297 case DirectiveEnum: \
298 CancelKind = Builder.getInt32(Value); \
299 break;
300#include "llvm/Frontend/OpenMP/OMPKinds.def"
301 default:
302 llvm_unreachable("Unknown cancel kind!");
303 }
304
305 Constant *SrcLocStr = getOrCreateSrcLocStr(Loc);
306 Value *Ident = getOrCreateIdent(SrcLocStr);
307 Value *Args[] = {Ident, getOrCreateThreadID(Ident), CancelKind};
308 Value *Result = Builder.CreateCall(
309 getOrCreateRuntimeFunction(OMPRTL___kmpc_cancel), Args);
310
311 // The actual cancel logic is shared with others, e.g., cancel_barriers.
312 emitCancelationCheckImpl(Result, CanceledDirective);
313
314 // Update the insertion point and remove the terminator we introduced.
315 Builder.SetInsertPoint(UI->getParent());
316 UI->eraseFromParent();
317
318 return Builder.saveIP();
319}
320
321void OpenMPIRBuilder::emitCancelationCheckImpl(
322 Value *CancelFlag, omp::Directive CanceledDirective) {
323 assert(isLastFinalizationInfoCancellable(CanceledDirective) &&
324 "Unexpected cancellation!");
325
326 // For a cancel barrier we create two new blocks.
327 BasicBlock *BB = Builder.GetInsertBlock();
328 BasicBlock *NonCancellationBlock;
329 if (Builder.GetInsertPoint() == BB->end()) {
330 // TODO: This branch will not be needed once we moved to the
331 // OpenMPIRBuilder codegen completely.
332 NonCancellationBlock = BasicBlock::Create(
333 BB->getContext(), BB->getName() + ".cont", BB->getParent());
334 } else {
335 NonCancellationBlock = SplitBlock(BB, &*Builder.GetInsertPoint());
336 BB->getTerminator()->eraseFromParent();
337 Builder.SetInsertPoint(BB);
338 }
339 BasicBlock *CancellationBlock = BasicBlock::Create(
340 BB->getContext(), BB->getName() + ".cncl", BB->getParent());
341
342 // Jump to them based on the return value.
343 Value *Cmp = Builder.CreateIsNull(CancelFlag);
344 Builder.CreateCondBr(Cmp, NonCancellationBlock, CancellationBlock,
345 /* TODO weight */ nullptr, nullptr);
346
347 // From the cancellation block we finalize all variables and go to the
348 // post finalization block that is known to the FiniCB callback.
349 Builder.SetInsertPoint(CancellationBlock);
350 auto &FI = FinalizationStack.back();
351 FI.FiniCB(Builder.saveIP());
352
353 // The continuation block is where code generation continues.
354 Builder.SetInsertPoint(NonCancellationBlock, NonCancellationBlock->begin());
355}
356
Johannes Doerferte4add9722019-12-25 16:59:38 -0600357IRBuilder<>::InsertPoint OpenMPIRBuilder::CreateParallel(
358 const LocationDescription &Loc, BodyGenCallbackTy BodyGenCB,
359 PrivatizeCallbackTy PrivCB, FinalizeCallbackTy FiniCB, Value *IfCondition,
360 Value *NumThreads, omp::ProcBindKind ProcBind, bool IsCancellable) {
361 if (!updateToLocation(Loc))
362 return Loc.IP;
363
364 Constant *SrcLocStr = getOrCreateSrcLocStr(Loc);
365 Value *Ident = getOrCreateIdent(SrcLocStr);
366 Value *ThreadID = getOrCreateThreadID(Ident);
367
368 if (NumThreads) {
369 // Build call __kmpc_push_num_threads(&Ident, global_tid, num_threads)
370 Value *Args[] = {
371 Ident, ThreadID,
372 Builder.CreateIntCast(NumThreads, Int32, /*isSigned*/ false)};
373 Builder.CreateCall(
374 getOrCreateRuntimeFunction(OMPRTL___kmpc_push_num_threads), Args);
375 }
376
Johannes Doerfert6c5d1f402019-12-25 18:15:36 -0600377 if (ProcBind != OMP_PROC_BIND_default) {
Johannes Doerferte4add9722019-12-25 16:59:38 -0600378 // Build call __kmpc_push_proc_bind(&Ident, global_tid, proc_bind)
379 Value *Args[] = {
380 Ident, ThreadID,
381 ConstantInt::get(Int32, unsigned(ProcBind), /*isSigned=*/true)};
382 Builder.CreateCall(getOrCreateRuntimeFunction(OMPRTL___kmpc_push_proc_bind),
383 Args);
384 }
385
386 BasicBlock *InsertBB = Builder.GetInsertBlock();
387 Function *OuterFn = InsertBB->getParent();
388
389 // Vector to remember instructions we used only during the modeling but which
390 // we want to delete at the end.
391 SmallVector<Instruction *, 4> ToBeDeleted;
392
393 Builder.SetInsertPoint(OuterFn->getEntryBlock().getFirstNonPHI());
394 AllocaInst *TIDAddr = Builder.CreateAlloca(Int32, nullptr, "tid.addr");
395 AllocaInst *ZeroAddr = Builder.CreateAlloca(Int32, nullptr, "zero.addr");
396
397 // If there is an if condition we actually use the TIDAddr and ZeroAddr in the
398 // program, otherwise we only need them for modeling purposes to get the
399 // associated arguments in the outlined function. In the former case,
400 // initialize the allocas properly, in the latter case, delete them later.
401 if (IfCondition) {
402 Builder.CreateStore(Constant::getNullValue(Int32), TIDAddr);
403 Builder.CreateStore(Constant::getNullValue(Int32), ZeroAddr);
404 } else {
405 ToBeDeleted.push_back(TIDAddr);
406 ToBeDeleted.push_back(ZeroAddr);
407 }
408
409 // Create an artificial insertion point that will also ensure the blocks we
410 // are about to split are not degenerated.
411 auto *UI = new UnreachableInst(Builder.getContext(), InsertBB);
412
413 Instruction *ThenTI = UI, *ElseTI = nullptr;
414 if (IfCondition)
415 SplitBlockAndInsertIfThenElse(IfCondition, UI, &ThenTI, &ElseTI);
416
417 BasicBlock *ThenBB = ThenTI->getParent();
418 BasicBlock *PRegEntryBB = ThenBB->splitBasicBlock(ThenTI, "omp.par.entry");
419 BasicBlock *PRegBodyBB =
420 PRegEntryBB->splitBasicBlock(ThenTI, "omp.par.region");
421 BasicBlock *PRegPreFiniBB =
422 PRegBodyBB->splitBasicBlock(ThenTI, "omp.par.pre_finalize");
423 BasicBlock *PRegExitBB =
424 PRegPreFiniBB->splitBasicBlock(ThenTI, "omp.par.exit");
425
426 auto FiniCBWrapper = [&](InsertPointTy IP) {
427 // Hide "open-ended" blocks from the given FiniCB by setting the right jump
428 // target to the region exit block.
429 if (IP.getBlock()->end() == IP.getPoint()) {
430 IRBuilder<>::InsertPointGuard IPG(Builder);
431 Builder.restoreIP(IP);
432 Instruction *I = Builder.CreateBr(PRegExitBB);
433 IP = InsertPointTy(I->getParent(), I->getIterator());
434 }
435 assert(IP.getBlock()->getTerminator()->getNumSuccessors() == 1 &&
436 IP.getBlock()->getTerminator()->getSuccessor(0) == PRegExitBB &&
437 "Unexpected insertion point for finalization call!");
438 return FiniCB(IP);
439 };
440
441 FinalizationStack.push_back({FiniCBWrapper, OMPD_parallel, IsCancellable});
442
443 // Generate the privatization allocas in the block that will become the entry
444 // of the outlined function.
445 InsertPointTy AllocaIP(PRegEntryBB,
446 PRegEntryBB->getTerminator()->getIterator());
447 Builder.restoreIP(AllocaIP);
448 AllocaInst *PrivTIDAddr =
449 Builder.CreateAlloca(Int32, nullptr, "tid.addr.local");
450 Instruction *PrivTID = Builder.CreateLoad(PrivTIDAddr, "tid");
451
452 // Add some fake uses for OpenMP provided arguments.
453 ToBeDeleted.push_back(Builder.CreateLoad(TIDAddr, "tid.addr.use"));
454 ToBeDeleted.push_back(Builder.CreateLoad(ZeroAddr, "zero.addr.use"));
455
456 // ThenBB
457 // |
458 // V
459 // PRegionEntryBB <- Privatization allocas are placed here.
460 // |
461 // V
462 // PRegionBodyBB <- BodeGen is invoked here.
463 // |
464 // V
465 // PRegPreFiniBB <- The block we will start finalization from.
466 // |
467 // V
468 // PRegionExitBB <- A common exit to simplify block collection.
469 //
470
Johannes Doerfert70cac412020-02-12 20:52:23 -0600471 LLVM_DEBUG(dbgs() << "Before body codegen: " << *OuterFn << "\n");
Johannes Doerferte4add9722019-12-25 16:59:38 -0600472
473 // Let the caller create the body.
474 assert(BodyGenCB && "Expected body generation callback!");
475 InsertPointTy CodeGenIP(PRegBodyBB, PRegBodyBB->begin());
476 BodyGenCB(AllocaIP, CodeGenIP, *PRegPreFiniBB);
477
Johannes Doerfert70cac412020-02-12 20:52:23 -0600478 LLVM_DEBUG(dbgs() << "After body codegen: " << *OuterFn << "\n");
Johannes Doerferte4add9722019-12-25 16:59:38 -0600479
Johannes Doerferte4add9722019-12-25 16:59:38 -0600480 FunctionCallee RTLFn = getOrCreateRuntimeFunction(OMPRTL___kmpc_fork_call);
Johannes Doerfert10fedd92019-12-26 11:23:38 -0600481 if (auto *F = dyn_cast<llvm::Function>(RTLFn.getCallee())) {
482 if (!F->hasMetadata(llvm::LLVMContext::MD_callback)) {
483 llvm::LLVMContext &Ctx = F->getContext();
484 MDBuilder MDB(Ctx);
485 // Annotate the callback behavior of the __kmpc_fork_call:
486 // - The callback callee is argument number 2 (microtask).
487 // - The first two arguments of the callback callee are unknown (-1).
488 // - All variadic arguments to the __kmpc_fork_call are passed to the
489 // callback callee.
490 F->addMetadata(
491 llvm::LLVMContext::MD_callback,
Johannes Doerfert70cac412020-02-12 20:52:23 -0600492 *llvm::MDNode::get(
493 Ctx, {MDB.createCallbackEncoding(2, {-1, -1},
494 /* VarArgsArePassed */ true)}));
Johannes Doerfert10fedd92019-12-26 11:23:38 -0600495 }
496 }
497
Johannes Doerfert3f3ec9c2020-02-13 00:39:55 -0600498 OutlineInfo OI;
Johannes Doerfert70cac412020-02-12 20:52:23 -0600499 OI.PostOutlineCB = [=](Function &OutlinedFn) {
500 // Add some known attributes.
501 OutlinedFn.addParamAttr(0, Attribute::NoAlias);
502 OutlinedFn.addParamAttr(1, Attribute::NoAlias);
503 OutlinedFn.addFnAttr(Attribute::NoUnwind);
504 OutlinedFn.addFnAttr(Attribute::NoRecurse);
Johannes Doerferte4add9722019-12-25 16:59:38 -0600505
Johannes Doerfert70cac412020-02-12 20:52:23 -0600506 assert(OutlinedFn.arg_size() >= 2 &&
507 "Expected at least tid and bounded tid as arguments");
508 unsigned NumCapturedVars =
509 OutlinedFn.arg_size() - /* tid & bounded tid */ 2;
Johannes Doerferte4add9722019-12-25 16:59:38 -0600510
Johannes Doerfert70cac412020-02-12 20:52:23 -0600511 CallInst *CI = cast<CallInst>(OutlinedFn.user_back());
512 CI->getParent()->setName("omp_parallel");
513 Builder.SetInsertPoint(CI);
Johannes Doerferte4add9722019-12-25 16:59:38 -0600514
Johannes Doerfert70cac412020-02-12 20:52:23 -0600515 // Build call __kmpc_fork_call(Ident, n, microtask, var1, .., varn);
516 Value *ForkCallArgs[] = {
517 Ident, Builder.getInt32(NumCapturedVars),
518 Builder.CreateBitCast(&OutlinedFn, ParallelTaskPtr)};
Johannes Doerferte4add9722019-12-25 16:59:38 -0600519
Johannes Doerfert70cac412020-02-12 20:52:23 -0600520 SmallVector<Value *, 16> RealArgs;
521 RealArgs.append(std::begin(ForkCallArgs), std::end(ForkCallArgs));
522 RealArgs.append(CI->arg_begin() + /* tid & bound tid */ 2, CI->arg_end());
Johannes Doerferte4add9722019-12-25 16:59:38 -0600523
Johannes Doerfert70cac412020-02-12 20:52:23 -0600524 Builder.CreateCall(RTLFn, RealArgs);
Johannes Doerferte4add9722019-12-25 16:59:38 -0600525
Johannes Doerfert70cac412020-02-12 20:52:23 -0600526 LLVM_DEBUG(dbgs() << "With fork_call placed: "
Johannes Doerferte4add9722019-12-25 16:59:38 -0600527 << *Builder.GetInsertBlock()->getParent() << "\n");
Johannes Doerfert70cac412020-02-12 20:52:23 -0600528
529 InsertPointTy ExitIP(PRegExitBB, PRegExitBB->end());
530
531 // Initialize the local TID stack location with the argument value.
532 Builder.SetInsertPoint(PrivTID);
533 Function::arg_iterator OutlinedAI = OutlinedFn.arg_begin();
534 Builder.CreateStore(Builder.CreateLoad(OutlinedAI), PrivTIDAddr);
535
536 // If no "if" clause was present we do not need the call created during
537 // outlining, otherwise we reuse it in the serialized parallel region.
538 if (!ElseTI) {
539 CI->eraseFromParent();
540 } else {
541
542 // If an "if" clause was present we are now generating the serialized
543 // version into the "else" branch.
544 Builder.SetInsertPoint(ElseTI);
545
546 // Build calls __kmpc_serialized_parallel(&Ident, GTid);
547 Value *SerializedParallelCallArgs[] = {Ident, ThreadID};
548 Builder.CreateCall(
549 getOrCreateRuntimeFunction(OMPRTL___kmpc_serialized_parallel),
550 SerializedParallelCallArgs);
551
552 // OutlinedFn(&GTid, &zero, CapturedStruct);
553 CI->removeFromParent();
554 Builder.Insert(CI);
555
556 // __kmpc_end_serialized_parallel(&Ident, GTid);
557 Value *EndArgs[] = {Ident, ThreadID};
558 Builder.CreateCall(
559 getOrCreateRuntimeFunction(OMPRTL___kmpc_end_serialized_parallel),
560 EndArgs);
561
562 LLVM_DEBUG(dbgs() << "With serialized parallel region: "
563 << *Builder.GetInsertBlock()->getParent() << "\n");
564 }
565
566 for (Instruction *I : ToBeDeleted)
567 I->eraseFromParent();
568 };
Johannes Doerferte4add9722019-12-25 16:59:38 -0600569
570 // Adjust the finalization stack, verify the adjustment, and call the
Johannes Doerfert70cac412020-02-12 20:52:23 -0600571 // finalize function a last time to finalize values between the pre-fini
572 // block and the exit block if we left the parallel "the normal way".
Johannes Doerferte4add9722019-12-25 16:59:38 -0600573 auto FiniInfo = FinalizationStack.pop_back_val();
574 (void)FiniInfo;
575 assert(FiniInfo.DK == OMPD_parallel &&
576 "Unexpected finalization stack state!");
577
Johannes Doerfert3f3ec9c2020-02-13 00:39:55 -0600578 Instruction *PRegPreFiniTI = PRegPreFiniBB->getTerminator();
579 assert(PRegPreFiniTI->getNumSuccessors() == 1 &&
580 PRegPreFiniTI->getSuccessor(0) == PRegExitBB &&
Johannes Doerferte4add9722019-12-25 16:59:38 -0600581 "Unexpected CFG structure!");
582
Johannes Doerfert3f3ec9c2020-02-13 00:39:55 -0600583 InsertPointTy PreFiniIP(PRegPreFiniBB, PRegPreFiniTI->getIterator());
Johannes Doerferte4add9722019-12-25 16:59:38 -0600584 FiniCB(PreFiniIP);
585
Johannes Doerfert3f3ec9c2020-02-13 00:39:55 -0600586 SmallPtrSet<BasicBlock *, 32> ParallelRegionBlockSet;
587 SmallVector<BasicBlock *, 32> Worklist;
588 ParallelRegionBlockSet.insert(PRegEntryBB);
589 ParallelRegionBlockSet.insert(PRegExitBB);
590
591 // Collect all blocks in-between PRegEntryBB and PRegExitBB.
592 Worklist.push_back(PRegEntryBB);
593 while (!Worklist.empty()) {
594 BasicBlock *BB = Worklist.pop_back_val();
595 OI.Blocks.push_back(BB);
596 for (BasicBlock *SuccBB : successors(BB))
597 if (ParallelRegionBlockSet.insert(SuccBB).second)
598 Worklist.push_back(SuccBB);
599 }
600
601 // Ensure a single exit node for the outlined region by creating one.
602 // We might have multiple incoming edges to the exit now due to finalizations,
603 // e.g., cancel calls that cause the control flow to leave the region.
604 BasicBlock *PRegOutlinedExitBB = PRegExitBB;
605 PRegExitBB = SplitBlock(PRegExitBB, &*PRegExitBB->getFirstInsertionPt());
606 PRegOutlinedExitBB->setName("omp.par.outlined.exit");
607 OI.Blocks.push_back(PRegOutlinedExitBB);
608
609 CodeExtractorAnalysisCache CEAC(*OuterFn);
610 CodeExtractor Extractor(OI.Blocks, /* DominatorTree */ nullptr,
611 /* AggregateArgs */ false,
612 /* BlockFrequencyInfo */ nullptr,
613 /* BranchProbabilityInfo */ nullptr,
614 /* AssumptionCache */ nullptr,
615 /* AllowVarArgs */ true,
616 /* AllowAlloca */ true,
617 /* Suffix */ ".omp_par");
618
619 // Find inputs to, outputs from the code region.
620 BasicBlock *CommonExit = nullptr;
621 SetVector<Value *> Inputs, Outputs, SinkingCands, HoistingCands;
622 Extractor.findAllocas(CEAC, SinkingCands, HoistingCands, CommonExit);
623 Extractor.findInputsOutputs(Inputs, Outputs, SinkingCands);
624
625 LLVM_DEBUG(dbgs() << "Before privatization: " << *OuterFn << "\n");
626
627 FunctionCallee TIDRTLFn =
628 getOrCreateRuntimeFunction(OMPRTL___kmpc_global_thread_num);
629
630 auto PrivHelper = [&](Value &V) {
631 if (&V == TIDAddr || &V == ZeroAddr)
632 return;
633
634 SmallVector<Use *, 8> Uses;
635 for (Use &U : V.uses())
636 if (auto *UserI = dyn_cast<Instruction>(U.getUser()))
637 if (ParallelRegionBlockSet.count(UserI->getParent()))
638 Uses.push_back(&U);
639
640 Value *ReplacementValue = nullptr;
641 CallInst *CI = dyn_cast<CallInst>(&V);
642 if (CI && CI->getCalledFunction() == TIDRTLFn.getCallee()) {
643 ReplacementValue = PrivTID;
644 } else {
645 Builder.restoreIP(
646 PrivCB(AllocaIP, Builder.saveIP(), V, ReplacementValue));
647 assert(ReplacementValue &&
648 "Expected copy/create callback to set replacement value!");
649 if (ReplacementValue == &V)
650 return;
651 }
652
653 for (Use *UPtr : Uses)
654 UPtr->set(ReplacementValue);
655 };
656
657 for (Value *Input : Inputs) {
658 LLVM_DEBUG(dbgs() << "Captured input: " << *Input << "\n");
659 PrivHelper(*Input);
660 }
661 assert(Outputs.empty() &&
662 "OpenMP outlining should not produce live-out values!");
663
664 LLVM_DEBUG(dbgs() << "After privatization: " << *OuterFn << "\n");
665 LLVM_DEBUG({
666 for (auto *BB : OI.Blocks)
667 dbgs() << " PBR: " << BB->getName() << "\n";
668 });
Johannes Doerfert70cac412020-02-12 20:52:23 -0600669
670 // Register the outlined info.
671 addOutlineInfo(std::move(OI));
Johannes Doerferte4add9722019-12-25 16:59:38 -0600672
Johannes Doerfert3f3ec9c2020-02-13 00:39:55 -0600673 InsertPointTy AfterIP(UI->getParent(), UI->getParent()->end());
674 UI->eraseFromParent();
675
Johannes Doerferte4add9722019-12-25 16:59:38 -0600676 return AfterIP;
677}
Kiran Chandramohana969e052020-02-04 21:43:40 +0000678
Fady Ghanim7438059a2020-02-15 00:42:23 -0600679void OpenMPIRBuilder::emitFlush(const LocationDescription &Loc) {
Kiran Chandramohana969e052020-02-04 21:43:40 +0000680 // Build call void __kmpc_flush(ident_t *loc)
681 Constant *SrcLocStr = getOrCreateSrcLocStr(Loc);
682 Value *Args[] = {getOrCreateIdent(SrcLocStr)};
683
684 Builder.CreateCall(getOrCreateRuntimeFunction(OMPRTL___kmpc_flush), Args);
685}
686
Fady Ghanim7438059a2020-02-15 00:42:23 -0600687void OpenMPIRBuilder::CreateFlush(const LocationDescription &Loc) {
Kiran Chandramohana969e052020-02-04 21:43:40 +0000688 if (!updateToLocation(Loc))
Fady Ghanim7438059a2020-02-15 00:42:23 -0600689 return;
Kiran Chandramohana969e052020-02-04 21:43:40 +0000690 emitFlush(Loc);
691}
Roger Ferrer Ibaneza82f35e2019-12-12 09:19:10 +0000692
693void OpenMPIRBuilder::emitTaskwaitImpl(const LocationDescription &Loc) {
694 // Build call kmp_int32 __kmpc_omp_taskwait(ident_t *loc, kmp_int32
695 // global_tid);
696 Constant *SrcLocStr = getOrCreateSrcLocStr(Loc);
697 Value *Ident = getOrCreateIdent(SrcLocStr);
698 Value *Args[] = {Ident, getOrCreateThreadID(Ident)};
699
700 // Ignore return result until untied tasks are supported.
701 Builder.CreateCall(getOrCreateRuntimeFunction(OMPRTL___kmpc_omp_taskwait),
702 Args);
703}
704
705void OpenMPIRBuilder::CreateTaskwait(const LocationDescription &Loc) {
706 if (!updateToLocation(Loc))
707 return;
708 emitTaskwaitImpl(Loc);
709}
Roger Ferrer Ibanez2bef1c02019-12-12 08:55:46 +0000710
711void OpenMPIRBuilder::emitTaskyieldImpl(const LocationDescription &Loc) {
712 // Build call __kmpc_omp_taskyield(loc, thread_id, 0);
713 Constant *SrcLocStr = getOrCreateSrcLocStr(Loc);
714 Value *Ident = getOrCreateIdent(SrcLocStr);
715 Constant *I32Null = ConstantInt::getNullValue(Int32);
716 Value *Args[] = {Ident, getOrCreateThreadID(Ident), I32Null};
717
718 Builder.CreateCall(getOrCreateRuntimeFunction(OMPRTL___kmpc_omp_taskyield),
719 Args);
720}
721
722void OpenMPIRBuilder::CreateTaskyield(const LocationDescription &Loc) {
723 if (!updateToLocation(Loc))
724 return;
725 emitTaskyieldImpl(Loc);
726}
Fady Ghanim7438059a2020-02-15 00:42:23 -0600727
728OpenMPIRBuilder::InsertPointTy
729OpenMPIRBuilder::CreateMaster(const LocationDescription &Loc,
730 BodyGenCallbackTy BodyGenCB,
731 FinalizeCallbackTy FiniCB) {
732
733 if (!updateToLocation(Loc))
734 return Loc.IP;
735
736 Directive OMPD = Directive::OMPD_master;
737 Constant *SrcLocStr = getOrCreateSrcLocStr(Loc);
738 Value *Ident = getOrCreateIdent(SrcLocStr);
739 Value *ThreadId = getOrCreateThreadID(Ident);
740 Value *Args[] = {Ident, ThreadId};
741
742 Function *EntryRTLFn = getOrCreateRuntimeFunction(OMPRTL___kmpc_master);
743 Instruction *EntryCall = Builder.CreateCall(EntryRTLFn, Args);
744
745 Function *ExitRTLFn = getOrCreateRuntimeFunction(OMPRTL___kmpc_end_master);
746 Instruction *ExitCall = Builder.CreateCall(ExitRTLFn, Args);
747
748 return EmitOMPInlinedRegion(OMPD, EntryCall, ExitCall, BodyGenCB, FiniCB,
749 /*Conditional*/ true, /*hasFinalize*/ true);
750}
751
752OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::CreateCritical(
753 const LocationDescription &Loc, BodyGenCallbackTy BodyGenCB,
754 FinalizeCallbackTy FiniCB, StringRef CriticalName, Value *HintInst) {
755
756 if (!updateToLocation(Loc))
757 return Loc.IP;
758
759 Directive OMPD = Directive::OMPD_critical;
760 Constant *SrcLocStr = getOrCreateSrcLocStr(Loc);
761 Value *Ident = getOrCreateIdent(SrcLocStr);
762 Value *ThreadId = getOrCreateThreadID(Ident);
763 Value *LockVar = getOMPCriticalRegionLock(CriticalName);
764 Value *Args[] = {Ident, ThreadId, LockVar};
765
766 SmallVector<llvm::Value *, 4> EnterArgs(std::begin(Args), std::end(Args));
767 Function *RTFn = nullptr;
768 if (HintInst) {
769 // Add Hint to entry Args and create call
770 EnterArgs.push_back(HintInst);
771 RTFn = getOrCreateRuntimeFunction(OMPRTL___kmpc_critical_with_hint);
772 } else {
773 RTFn = getOrCreateRuntimeFunction(OMPRTL___kmpc_critical);
774 }
775 Instruction *EntryCall = Builder.CreateCall(RTFn, EnterArgs);
776
777 Function *ExitRTLFn = getOrCreateRuntimeFunction(OMPRTL___kmpc_end_critical);
778 Instruction *ExitCall = Builder.CreateCall(ExitRTLFn, Args);
779
780 return EmitOMPInlinedRegion(OMPD, EntryCall, ExitCall, BodyGenCB, FiniCB,
781 /*Conditional*/ false, /*hasFinalize*/ true);
782}
783
784OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::EmitOMPInlinedRegion(
785 Directive OMPD, Instruction *EntryCall, Instruction *ExitCall,
786 BodyGenCallbackTy BodyGenCB, FinalizeCallbackTy FiniCB, bool Conditional,
787 bool HasFinalize) {
788
789 if (HasFinalize)
790 FinalizationStack.push_back({FiniCB, OMPD, /*IsCancellable*/ false});
791
792 // Create inlined region's entry and body blocks, in preparation
793 // for conditional creation
794 BasicBlock *EntryBB = Builder.GetInsertBlock();
795 Instruction *SplitPos = EntryBB->getTerminator();
796 if (!isa_and_nonnull<BranchInst>(SplitPos))
797 SplitPos = new UnreachableInst(Builder.getContext(), EntryBB);
798 BasicBlock *ExitBB = EntryBB->splitBasicBlock(SplitPos, "omp_region.end");
799 BasicBlock *FiniBB =
800 EntryBB->splitBasicBlock(EntryBB->getTerminator(), "omp_region.finalize");
801
802 Builder.SetInsertPoint(EntryBB->getTerminator());
803 emitCommonDirectiveEntry(OMPD, EntryCall, ExitBB, Conditional);
804
805 // generate body
806 BodyGenCB(/* AllocaIP */ InsertPointTy(),
807 /* CodeGenIP */ Builder.saveIP(), *FiniBB);
808
809 // If we didn't emit a branch to FiniBB during body generation, it means
810 // FiniBB is unreachable (e.g. while(1);). stop generating all the
811 // unreachable blocks, and remove anything we are not going to use.
812 auto SkipEmittingRegion = FiniBB->hasNPredecessors(0);
813 if (SkipEmittingRegion) {
814 FiniBB->eraseFromParent();
815 ExitCall->eraseFromParent();
816 // Discard finalization if we have it.
817 if (HasFinalize) {
818 assert(!FinalizationStack.empty() &&
819 "Unexpected finalization stack state!");
820 FinalizationStack.pop_back();
821 }
822 } else {
823 // emit exit call and do any needed finalization.
824 auto FinIP = InsertPointTy(FiniBB, FiniBB->getFirstInsertionPt());
825 assert(FiniBB->getTerminator()->getNumSuccessors() == 1 &&
826 FiniBB->getTerminator()->getSuccessor(0) == ExitBB &&
827 "Unexpected control flow graph state!!");
828 emitCommonDirectiveExit(OMPD, FinIP, ExitCall, HasFinalize);
829 assert(FiniBB->getUniquePredecessor()->getUniqueSuccessor() == FiniBB &&
830 "Unexpected Control Flow State!");
831 MergeBlockIntoPredecessor(FiniBB);
832 }
833
834 // If we are skipping the region of a non conditional, remove the exit
835 // block, and clear the builder's insertion point.
836 assert(SplitPos->getParent() == ExitBB &&
837 "Unexpected Insertion point location!");
838 if (!Conditional && SkipEmittingRegion) {
839 ExitBB->eraseFromParent();
840 Builder.ClearInsertionPoint();
841 } else {
842 auto merged = MergeBlockIntoPredecessor(ExitBB);
843 BasicBlock *ExitPredBB = SplitPos->getParent();
844 auto InsertBB = merged ? ExitPredBB : ExitBB;
845 if (!isa_and_nonnull<BranchInst>(SplitPos))
846 SplitPos->eraseFromParent();
847 Builder.SetInsertPoint(InsertBB);
848 }
849
850 return Builder.saveIP();
851}
852
853OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::emitCommonDirectiveEntry(
854 Directive OMPD, Value *EntryCall, BasicBlock *ExitBB, bool Conditional) {
855
856 // if nothing to do, Return current insertion point.
857 if (!Conditional)
858 return Builder.saveIP();
859
860 BasicBlock *EntryBB = Builder.GetInsertBlock();
861 Value *CallBool = Builder.CreateIsNotNull(EntryCall);
862 auto *ThenBB = BasicBlock::Create(M.getContext(), "omp_region.body");
863 auto *UI = new UnreachableInst(Builder.getContext(), ThenBB);
864
865 // Emit thenBB and set the Builder's insertion point there for
866 // body generation next. Place the block after the current block.
867 Function *CurFn = EntryBB->getParent();
868 CurFn->getBasicBlockList().insertAfter(EntryBB->getIterator(), ThenBB);
869
870 // Move Entry branch to end of ThenBB, and replace with conditional
871 // branch (If-stmt)
872 Instruction *EntryBBTI = EntryBB->getTerminator();
873 Builder.CreateCondBr(CallBool, ThenBB, ExitBB);
874 EntryBBTI->removeFromParent();
875 Builder.SetInsertPoint(UI);
876 Builder.Insert(EntryBBTI);
877 UI->eraseFromParent();
878 Builder.SetInsertPoint(ThenBB->getTerminator());
879
880 // return an insertion point to ExitBB.
881 return IRBuilder<>::InsertPoint(ExitBB, ExitBB->getFirstInsertionPt());
882}
883
884OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::emitCommonDirectiveExit(
885 omp::Directive OMPD, InsertPointTy FinIP, Instruction *ExitCall,
886 bool HasFinalize) {
887
888 Builder.restoreIP(FinIP);
889
890 // If there is finalization to do, emit it before the exit call
891 if (HasFinalize) {
892 assert(!FinalizationStack.empty() &&
893 "Unexpected finalization stack state!");
894
895 FinalizationInfo Fi = FinalizationStack.pop_back_val();
896 assert(Fi.DK == OMPD && "Unexpected Directive for Finalization call!");
897
898 Fi.FiniCB(FinIP);
899
900 BasicBlock *FiniBB = FinIP.getBlock();
901 Instruction *FiniBBTI = FiniBB->getTerminator();
902
903 // set Builder IP for call creation
904 Builder.SetInsertPoint(FiniBBTI);
905 }
906
907 // place the Exitcall as last instruction before Finalization block terminator
908 ExitCall->removeFromParent();
909 Builder.Insert(ExitCall);
910
911 return IRBuilder<>::InsertPoint(ExitCall->getParent(),
912 ExitCall->getIterator());
913}
914
915std::string OpenMPIRBuilder::getNameWithSeparators(ArrayRef<StringRef> Parts,
916 StringRef FirstSeparator,
917 StringRef Separator) {
918 SmallString<128> Buffer;
919 llvm::raw_svector_ostream OS(Buffer);
920 StringRef Sep = FirstSeparator;
921 for (StringRef Part : Parts) {
922 OS << Sep << Part;
923 Sep = Separator;
924 }
925 return OS.str().str();
926}
927
928Constant *OpenMPIRBuilder::getOrCreateOMPInternalVariable(
929 llvm::Type *Ty, const llvm::Twine &Name, unsigned AddressSpace) {
930 // TODO: Replace the twine arg with stringref to get rid of the conversion
931 // logic. However This is taken from current implementation in clang as is.
932 // Since this method is used in many places exclusively for OMP internal use
933 // we will keep it as is for temporarily until we move all users to the
934 // builder and then, if possible, fix it everywhere in one go.
935 SmallString<256> Buffer;
936 llvm::raw_svector_ostream Out(Buffer);
937 Out << Name;
938 StringRef RuntimeName = Out.str();
939 auto &Elem = *InternalVars.try_emplace(RuntimeName, nullptr).first;
940 if (Elem.second) {
941 assert(Elem.second->getType()->getPointerElementType() == Ty &&
942 "OMP internal variable has different type than requested");
943 } else {
944 // TODO: investigate the appropriate linkage type used for the global
945 // variable for possibly changing that to internal or private, or maybe
946 // create different versions of the function for different OMP internal
947 // variables.
948 Elem.second = new llvm::GlobalVariable(
949 M, Ty, /*IsConstant*/ false, llvm::GlobalValue::CommonLinkage,
950 llvm::Constant::getNullValue(Ty), Elem.first(),
951 /*InsertBefore=*/nullptr, llvm::GlobalValue::NotThreadLocal,
952 AddressSpace);
953 }
954
955 return Elem.second;
956}
957
958Value *OpenMPIRBuilder::getOMPCriticalRegionLock(StringRef CriticalName) {
959 std::string Prefix = Twine("gomp_critical_user_", CriticalName).str();
960 std::string Name = getNameWithSeparators({Prefix, "var"}, ".", ".");
961 return getOrCreateOMPInternalVariable(KmpCriticalNameTy, Name);
962}