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