| Johannes Doerfert | d23c614 | 2019-11-05 18:57:44 -0600 | [diff] [blame] | 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" |
| Johannes Doerfert | e4add972 | 2019-12-25 16:59:38 -0600 | [diff] [blame] | 19 | #include "llvm/IR/CFG.h" |
| Johannes Doerfert | d23c614 | 2019-11-05 18:57:44 -0600 | [diff] [blame] | 20 | #include "llvm/IR/DebugInfo.h" |
| Kadir Cetinkaya | 5731b66 | 2020-02-10 14:44:51 +0100 | [diff] [blame] | 21 | #include "llvm/IR/IRBuilder.h" |
| Fady Ghanim | 7438059a | 2020-02-15 00:42:23 -0600 | [diff] [blame] | 22 | #include "llvm/IR/MDBuilder.h" |
| Johannes Doerfert | d23c614 | 2019-11-05 18:57:44 -0600 | [diff] [blame] | 23 | #include "llvm/Support/CommandLine.h" |
| Johannes Doerfert | e4add972 | 2019-12-25 16:59:38 -0600 | [diff] [blame] | 24 | #include "llvm/Support/Error.h" |
| Johannes Doerfert | d23c614 | 2019-11-05 18:57:44 -0600 | [diff] [blame] | 25 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" |
| Johannes Doerfert | e4add972 | 2019-12-25 16:59:38 -0600 | [diff] [blame] | 26 | #include "llvm/Transforms/Utils/CodeExtractor.h" |
| Johannes Doerfert | d23c614 | 2019-11-05 18:57:44 -0600 | [diff] [blame] | 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 | |
| Johannes Doerfert | 70cac41 | 2020-02-12 20:52:23 -0600 | [diff] [blame] | 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"); |
| Johannes Doerfert | 3f3ec9c | 2020-02-13 00:39:55 -0600 | [diff] [blame] | 113 | assert(Extractor.isEligible() && |
| 114 | "Expected OpenMP outlining to be possible!"); |
| Johannes Doerfert | 70cac41 | 2020-02-12 20:52:23 -0600 | [diff] [blame] | 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 | |
| Johannes Doerfert | d23c614 | 2019-11-05 18:57:44 -0600 | [diff] [blame] | 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. |
| Johannes Doerfert | f9c3c5da | 2019-12-25 10:33:56 -0600 | [diff] [blame] | 265 | bool UseCancelBarrier = |
| 266 | !ForceSimpleCall && isLastFinalizationInfoCancellable(OMPD_parallel); |
| Johannes Doerfert | d23c614 | 2019-11-05 18:57:44 -0600 | [diff] [blame] | 267 | |
| 268 | Value *Result = Builder.CreateCall( |
| 269 | getOrCreateRuntimeFunction(UseCancelBarrier ? OMPRTL___kmpc_cancel_barrier |
| 270 | : OMPRTL___kmpc_barrier), |
| 271 | Args); |
| 272 | |
| Johannes Doerfert | 000c6a5 | 2019-12-27 15:53:37 -0600 | [diff] [blame] | 273 | if (UseCancelBarrier && CheckCancelFlag) |
| 274 | emitCancelationCheckImpl(Result, OMPD_parallel); |
| Johannes Doerfert | d23c614 | 2019-11-05 18:57:44 -0600 | [diff] [blame] | 275 | |
| 276 | return Builder.saveIP(); |
| 277 | } |
| Johannes Doerfert | e4add972 | 2019-12-25 16:59:38 -0600 | [diff] [blame] | 278 | |
| Johannes Doerfert | 000c6a5 | 2019-12-27 15:53:37 -0600 | [diff] [blame] | 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 | |
| Johannes Doerfert | e4add972 | 2019-12-25 16:59:38 -0600 | [diff] [blame] | 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 | |
| Johannes Doerfert | 6c5d1f40 | 2019-12-25 18:15:36 -0600 | [diff] [blame] | 377 | if (ProcBind != OMP_PROC_BIND_default) { |
| Johannes Doerfert | e4add972 | 2019-12-25 16:59:38 -0600 | [diff] [blame] | 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 | |
| Johannes Doerfert | 70cac41 | 2020-02-12 20:52:23 -0600 | [diff] [blame] | 471 | LLVM_DEBUG(dbgs() << "Before body codegen: " << *OuterFn << "\n"); |
| Johannes Doerfert | e4add972 | 2019-12-25 16:59:38 -0600 | [diff] [blame] | 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 | |
| Johannes Doerfert | 70cac41 | 2020-02-12 20:52:23 -0600 | [diff] [blame] | 478 | LLVM_DEBUG(dbgs() << "After body codegen: " << *OuterFn << "\n"); |
| Johannes Doerfert | e4add972 | 2019-12-25 16:59:38 -0600 | [diff] [blame] | 479 | |
| Johannes Doerfert | e4add972 | 2019-12-25 16:59:38 -0600 | [diff] [blame] | 480 | FunctionCallee RTLFn = getOrCreateRuntimeFunction(OMPRTL___kmpc_fork_call); |
| Johannes Doerfert | 10fedd9 | 2019-12-26 11:23:38 -0600 | [diff] [blame] | 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, |
| Johannes Doerfert | 70cac41 | 2020-02-12 20:52:23 -0600 | [diff] [blame] | 492 | *llvm::MDNode::get( |
| 493 | Ctx, {MDB.createCallbackEncoding(2, {-1, -1}, |
| 494 | /* VarArgsArePassed */ true)})); |
| Johannes Doerfert | 10fedd9 | 2019-12-26 11:23:38 -0600 | [diff] [blame] | 495 | } |
| 496 | } |
| 497 | |
| Johannes Doerfert | 3f3ec9c | 2020-02-13 00:39:55 -0600 | [diff] [blame] | 498 | OutlineInfo OI; |
| Johannes Doerfert | 70cac41 | 2020-02-12 20:52:23 -0600 | [diff] [blame] | 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); |
| Johannes Doerfert | e4add972 | 2019-12-25 16:59:38 -0600 | [diff] [blame] | 505 | |
| Johannes Doerfert | 70cac41 | 2020-02-12 20:52:23 -0600 | [diff] [blame] | 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; |
| Johannes Doerfert | e4add972 | 2019-12-25 16:59:38 -0600 | [diff] [blame] | 510 | |
| Johannes Doerfert | 70cac41 | 2020-02-12 20:52:23 -0600 | [diff] [blame] | 511 | CallInst *CI = cast<CallInst>(OutlinedFn.user_back()); |
| 512 | CI->getParent()->setName("omp_parallel"); |
| 513 | Builder.SetInsertPoint(CI); |
| Johannes Doerfert | e4add972 | 2019-12-25 16:59:38 -0600 | [diff] [blame] | 514 | |
| Johannes Doerfert | 70cac41 | 2020-02-12 20:52:23 -0600 | [diff] [blame] | 515 | // Build call __kmpc_fork_call(Ident, n, microtask, var1, .., varn); |
| 516 | Value *ForkCallArgs[] = { |
| 517 | Ident, Builder.getInt32(NumCapturedVars), |
| 518 | Builder.CreateBitCast(&OutlinedFn, ParallelTaskPtr)}; |
| Johannes Doerfert | e4add972 | 2019-12-25 16:59:38 -0600 | [diff] [blame] | 519 | |
| Johannes Doerfert | 70cac41 | 2020-02-12 20:52:23 -0600 | [diff] [blame] | 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()); |
| Johannes Doerfert | e4add972 | 2019-12-25 16:59:38 -0600 | [diff] [blame] | 523 | |
| Johannes Doerfert | 70cac41 | 2020-02-12 20:52:23 -0600 | [diff] [blame] | 524 | Builder.CreateCall(RTLFn, RealArgs); |
| Johannes Doerfert | e4add972 | 2019-12-25 16:59:38 -0600 | [diff] [blame] | 525 | |
| Johannes Doerfert | 70cac41 | 2020-02-12 20:52:23 -0600 | [diff] [blame] | 526 | LLVM_DEBUG(dbgs() << "With fork_call placed: " |
| Johannes Doerfert | e4add972 | 2019-12-25 16:59:38 -0600 | [diff] [blame] | 527 | << *Builder.GetInsertBlock()->getParent() << "\n"); |
| Johannes Doerfert | 70cac41 | 2020-02-12 20:52:23 -0600 | [diff] [blame] | 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 | }; |
| Johannes Doerfert | e4add972 | 2019-12-25 16:59:38 -0600 | [diff] [blame] | 569 | |
| 570 | // Adjust the finalization stack, verify the adjustment, and call the |
| Johannes Doerfert | 70cac41 | 2020-02-12 20:52:23 -0600 | [diff] [blame] | 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". |
| Johannes Doerfert | e4add972 | 2019-12-25 16:59:38 -0600 | [diff] [blame] | 573 | auto FiniInfo = FinalizationStack.pop_back_val(); |
| 574 | (void)FiniInfo; |
| 575 | assert(FiniInfo.DK == OMPD_parallel && |
| 576 | "Unexpected finalization stack state!"); |
| 577 | |
| Johannes Doerfert | 3f3ec9c | 2020-02-13 00:39:55 -0600 | [diff] [blame] | 578 | Instruction *PRegPreFiniTI = PRegPreFiniBB->getTerminator(); |
| 579 | assert(PRegPreFiniTI->getNumSuccessors() == 1 && |
| 580 | PRegPreFiniTI->getSuccessor(0) == PRegExitBB && |
| Johannes Doerfert | e4add972 | 2019-12-25 16:59:38 -0600 | [diff] [blame] | 581 | "Unexpected CFG structure!"); |
| 582 | |
| Johannes Doerfert | 3f3ec9c | 2020-02-13 00:39:55 -0600 | [diff] [blame] | 583 | InsertPointTy PreFiniIP(PRegPreFiniBB, PRegPreFiniTI->getIterator()); |
| Johannes Doerfert | e4add972 | 2019-12-25 16:59:38 -0600 | [diff] [blame] | 584 | FiniCB(PreFiniIP); |
| 585 | |
| Johannes Doerfert | 3f3ec9c | 2020-02-13 00:39:55 -0600 | [diff] [blame] | 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 | }); |
| Johannes Doerfert | 70cac41 | 2020-02-12 20:52:23 -0600 | [diff] [blame] | 669 | |
| 670 | // Register the outlined info. |
| 671 | addOutlineInfo(std::move(OI)); |
| Johannes Doerfert | e4add972 | 2019-12-25 16:59:38 -0600 | [diff] [blame] | 672 | |
| Johannes Doerfert | 3f3ec9c | 2020-02-13 00:39:55 -0600 | [diff] [blame] | 673 | InsertPointTy AfterIP(UI->getParent(), UI->getParent()->end()); |
| 674 | UI->eraseFromParent(); |
| 675 | |
| Johannes Doerfert | e4add972 | 2019-12-25 16:59:38 -0600 | [diff] [blame] | 676 | return AfterIP; |
| 677 | } |
| Kiran Chandramohan | a969e05 | 2020-02-04 21:43:40 +0000 | [diff] [blame] | 678 | |
| Fady Ghanim | 7438059a | 2020-02-15 00:42:23 -0600 | [diff] [blame] | 679 | void OpenMPIRBuilder::emitFlush(const LocationDescription &Loc) { |
| Kiran Chandramohan | a969e05 | 2020-02-04 21:43:40 +0000 | [diff] [blame] | 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 | |
| Fady Ghanim | 7438059a | 2020-02-15 00:42:23 -0600 | [diff] [blame] | 687 | void OpenMPIRBuilder::CreateFlush(const LocationDescription &Loc) { |
| Kiran Chandramohan | a969e05 | 2020-02-04 21:43:40 +0000 | [diff] [blame] | 688 | if (!updateToLocation(Loc)) |
| Fady Ghanim | 7438059a | 2020-02-15 00:42:23 -0600 | [diff] [blame] | 689 | return; |
| Kiran Chandramohan | a969e05 | 2020-02-04 21:43:40 +0000 | [diff] [blame] | 690 | emitFlush(Loc); |
| 691 | } |
| Roger Ferrer Ibanez | a82f35e | 2019-12-12 09:19:10 +0000 | [diff] [blame] | 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 | } |
| Roger Ferrer Ibanez | 2bef1c0 | 2019-12-12 08:55:46 +0000 | [diff] [blame] | 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 | } |
| Fady Ghanim | 7438059a | 2020-02-15 00:42:23 -0600 | [diff] [blame] | 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 | } |