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