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