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