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