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