1 //===- OpenMPToLLVMIRTranslation.cpp - Translate OpenMP dialect to LLVM IR-===// 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 // 9 // This file implements a translation between the MLIR OpenMP dialect and LLVM 10 // IR. 11 // 12 //===----------------------------------------------------------------------===// 13 #include "mlir/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.h" 14 #include "mlir/Dialect/OpenMP/OpenMPDialect.h" 15 #include "mlir/IR/BlockAndValueMapping.h" 16 #include "mlir/IR/Operation.h" 17 #include "mlir/Support/LLVM.h" 18 #include "mlir/Target/LLVMIR/ModuleTranslation.h" 19 20 #include "llvm/ADT/SetVector.h" 21 #include "llvm/ADT/TypeSwitch.h" 22 #include "llvm/Frontend/OpenMP/OMPIRBuilder.h" 23 #include "llvm/IR/IRBuilder.h" 24 25 using namespace mlir; 26 27 namespace { 28 /// ModuleTranslation stack frame for OpenMP operations. This keeps track of the 29 /// insertion points for allocas. 30 class OpenMPAllocaStackFrame 31 : public LLVM::ModuleTranslation::StackFrameBase<OpenMPAllocaStackFrame> { 32 public: 33 explicit OpenMPAllocaStackFrame(llvm::OpenMPIRBuilder::InsertPointTy allocaIP) 34 : allocaInsertPoint(allocaIP) {} 35 llvm::OpenMPIRBuilder::InsertPointTy allocaInsertPoint; 36 }; 37 38 /// ModuleTranslation stack frame containing the partial mapping between MLIR 39 /// values and their LLVM IR equivalents. 40 class OpenMPVarMappingStackFrame 41 : public LLVM::ModuleTranslation::StackFrameBase< 42 OpenMPVarMappingStackFrame> { 43 public: 44 explicit OpenMPVarMappingStackFrame( 45 const DenseMap<Value, llvm::Value *> &mapping) 46 : mapping(mapping) {} 47 48 DenseMap<Value, llvm::Value *> mapping; 49 }; 50 } // namespace 51 52 /// Find the insertion point for allocas given the current insertion point for 53 /// normal operations in the builder. 54 static llvm::OpenMPIRBuilder::InsertPointTy 55 findAllocaInsertPoint(llvm::IRBuilderBase &builder, 56 const LLVM::ModuleTranslation &moduleTranslation) { 57 // If there is an alloca insertion point on stack, i.e. we are in a nested 58 // operation and a specific point was provided by some surrounding operation, 59 // use it. 60 llvm::OpenMPIRBuilder::InsertPointTy allocaInsertPoint; 61 WalkResult walkResult = moduleTranslation.stackWalk<OpenMPAllocaStackFrame>( 62 [&](const OpenMPAllocaStackFrame &frame) { 63 allocaInsertPoint = frame.allocaInsertPoint; 64 return WalkResult::interrupt(); 65 }); 66 if (walkResult.wasInterrupted()) 67 return allocaInsertPoint; 68 69 // Otherwise, insert to the entry block of the surrounding function. 70 llvm::BasicBlock &funcEntryBlock = 71 builder.GetInsertBlock()->getParent()->getEntryBlock(); 72 return llvm::OpenMPIRBuilder::InsertPointTy( 73 &funcEntryBlock, funcEntryBlock.getFirstInsertionPt()); 74 } 75 76 /// Converts the given region that appears within an OpenMP dialect operation to 77 /// LLVM IR, creating a branch from the `sourceBlock` to the entry block of the 78 /// region, and a branch from any block with an successor-less OpenMP terminator 79 /// to `continuationBlock`. Populates `continuationBlockPHIs` with the PHI nodes 80 /// of the continuation block if provided. 81 static void convertOmpOpRegions( 82 Region ®ion, StringRef blockName, llvm::BasicBlock &sourceBlock, 83 llvm::BasicBlock &continuationBlock, llvm::IRBuilderBase &builder, 84 LLVM::ModuleTranslation &moduleTranslation, LogicalResult &bodyGenStatus, 85 SmallVectorImpl<llvm::PHINode *> *continuationBlockPHIs = nullptr) { 86 llvm::LLVMContext &llvmContext = builder.getContext(); 87 for (Block &bb : region) { 88 llvm::BasicBlock *llvmBB = llvm::BasicBlock::Create( 89 llvmContext, blockName, builder.GetInsertBlock()->getParent(), 90 builder.GetInsertBlock()->getNextNode()); 91 moduleTranslation.mapBlock(&bb, llvmBB); 92 } 93 94 llvm::Instruction *sourceTerminator = sourceBlock.getTerminator(); 95 96 // Terminators (namely YieldOp) may be forwarding values to the region that 97 // need to be available in the continuation block. Collect the types of these 98 // operands in preparation of creating PHI nodes. 99 SmallVector<llvm::Type *> continuationBlockPHITypes; 100 bool operandsProcessed = false; 101 unsigned numYields = 0; 102 for (Block &bb : region.getBlocks()) { 103 if (omp::YieldOp yield = dyn_cast<omp::YieldOp>(bb.getTerminator())) { 104 if (!operandsProcessed) { 105 for (unsigned i = 0, e = yield->getNumOperands(); i < e; ++i) { 106 continuationBlockPHITypes.push_back( 107 moduleTranslation.convertType(yield->getOperand(i).getType())); 108 } 109 operandsProcessed = true; 110 } else { 111 assert(continuationBlockPHITypes.size() == yield->getNumOperands() && 112 "mismatching number of values yielded from the region"); 113 for (unsigned i = 0, e = yield->getNumOperands(); i < e; ++i) { 114 llvm::Type *operandType = 115 moduleTranslation.convertType(yield->getOperand(i).getType()); 116 (void)operandType; 117 assert(continuationBlockPHITypes[i] == operandType && 118 "values of mismatching types yielded from the region"); 119 } 120 } 121 numYields++; 122 } 123 } 124 125 // Insert PHI nodes in the continuation block for any values forwarded by the 126 // terminators in this region. 127 if (!continuationBlockPHITypes.empty()) 128 assert( 129 continuationBlockPHIs && 130 "expected continuation block PHIs if converted regions yield values"); 131 if (continuationBlockPHIs) { 132 llvm::IRBuilderBase::InsertPointGuard guard(builder); 133 continuationBlockPHIs->reserve(continuationBlockPHITypes.size()); 134 builder.SetInsertPoint(&continuationBlock, continuationBlock.begin()); 135 for (llvm::Type *ty : continuationBlockPHITypes) 136 continuationBlockPHIs->push_back(builder.CreatePHI(ty, numYields)); 137 } 138 139 // Convert blocks one by one in topological order to ensure 140 // defs are converted before uses. 141 SetVector<Block *> blocks = 142 LLVM::detail::getTopologicallySortedBlocks(region); 143 for (Block *bb : blocks) { 144 llvm::BasicBlock *llvmBB = moduleTranslation.lookupBlock(bb); 145 // Retarget the branch of the entry block to the entry block of the 146 // converted region (regions are single-entry). 147 if (bb->isEntryBlock()) { 148 assert(sourceTerminator->getNumSuccessors() == 1 && 149 "provided entry block has multiple successors"); 150 assert(sourceTerminator->getSuccessor(0) == &continuationBlock && 151 "ContinuationBlock is not the successor of the entry block"); 152 sourceTerminator->setSuccessor(0, llvmBB); 153 } 154 155 llvm::IRBuilderBase::InsertPointGuard guard(builder); 156 if (failed( 157 moduleTranslation.convertBlock(*bb, bb->isEntryBlock(), builder))) { 158 bodyGenStatus = failure(); 159 return; 160 } 161 162 // Special handling for `omp.yield` and `omp.terminator` (we may have more 163 // than one): they return the control to the parent OpenMP dialect operation 164 // so replace them with the branch to the continuation block. We handle this 165 // here to avoid relying inter-function communication through the 166 // ModuleTranslation class to set up the correct insertion point. This is 167 // also consistent with MLIR's idiom of handling special region terminators 168 // in the same code that handles the region-owning operation. 169 Operation *terminator = bb->getTerminator(); 170 if (isa<omp::TerminatorOp, omp::YieldOp>(terminator)) { 171 builder.CreateBr(&continuationBlock); 172 173 for (unsigned i = 0, e = terminator->getNumOperands(); i < e; ++i) 174 (*continuationBlockPHIs)[i]->addIncoming( 175 moduleTranslation.lookupValue(terminator->getOperand(i)), llvmBB); 176 } 177 } 178 // After all blocks have been traversed and values mapped, connect the PHI 179 // nodes to the results of preceding blocks. 180 LLVM::detail::connectPHINodes(region, moduleTranslation); 181 182 // Remove the blocks and values defined in this region from the mapping since 183 // they are not visible outside of this region. This allows the same region to 184 // be converted several times, that is cloned, without clashes, and slightly 185 // speeds up the lookups. 186 moduleTranslation.forgetMapping(region); 187 } 188 189 /// Convert ProcBindKind from MLIR-generated enum to LLVM enum. 190 static llvm::omp::ProcBindKind getProcBindKind(omp::ClauseProcBindKind kind) { 191 switch (kind) { 192 case omp::ClauseProcBindKind::close: 193 return llvm::omp::ProcBindKind::OMP_PROC_BIND_close; 194 case omp::ClauseProcBindKind::master: 195 return llvm::omp::ProcBindKind::OMP_PROC_BIND_master; 196 case omp::ClauseProcBindKind::primary: 197 return llvm::omp::ProcBindKind::OMP_PROC_BIND_primary; 198 case omp::ClauseProcBindKind::spread: 199 return llvm::omp::ProcBindKind::OMP_PROC_BIND_spread; 200 } 201 } 202 203 /// Converts the OpenMP parallel operation to LLVM IR. 204 static LogicalResult 205 convertOmpParallel(omp::ParallelOp opInst, llvm::IRBuilderBase &builder, 206 LLVM::ModuleTranslation &moduleTranslation) { 207 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy; 208 // TODO: support error propagation in OpenMPIRBuilder and use it instead of 209 // relying on captured variables. 210 LogicalResult bodyGenStatus = success(); 211 212 auto bodyGenCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP, 213 llvm::BasicBlock &continuationBlock) { 214 // Save the alloca insertion point on ModuleTranslation stack for use in 215 // nested regions. 216 LLVM::ModuleTranslation::SaveStack<OpenMPAllocaStackFrame> frame( 217 moduleTranslation, allocaIP); 218 219 // ParallelOp has only one region associated with it. 220 convertOmpOpRegions(opInst.getRegion(), "omp.par.region", 221 *codeGenIP.getBlock(), continuationBlock, builder, 222 moduleTranslation, bodyGenStatus); 223 }; 224 225 // TODO: Perform appropriate actions according to the data-sharing 226 // attribute (shared, private, firstprivate, ...) of variables. 227 // Currently defaults to shared. 228 auto privCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP, 229 llvm::Value &, llvm::Value &vPtr, 230 llvm::Value *&replacementValue) -> InsertPointTy { 231 replacementValue = &vPtr; 232 233 return codeGenIP; 234 }; 235 236 // TODO: Perform finalization actions for variables. This has to be 237 // called for variables which have destructors/finalizers. 238 auto finiCB = [&](InsertPointTy codeGenIP) {}; 239 240 llvm::Value *ifCond = nullptr; 241 if (auto ifExprVar = opInst.if_expr_var()) 242 ifCond = moduleTranslation.lookupValue(ifExprVar); 243 llvm::Value *numThreads = nullptr; 244 if (auto numThreadsVar = opInst.num_threads_var()) 245 numThreads = moduleTranslation.lookupValue(numThreadsVar); 246 auto pbKind = llvm::omp::OMP_PROC_BIND_default; 247 if (auto bind = opInst.proc_bind_val()) 248 pbKind = getProcBindKind(*bind); 249 // TODO: Is the Parallel construct cancellable? 250 bool isCancellable = false; 251 252 llvm::OpenMPIRBuilder::LocationDescription ompLoc( 253 builder.saveIP(), builder.getCurrentDebugLocation()); 254 builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createParallel( 255 ompLoc, findAllocaInsertPoint(builder, moduleTranslation), bodyGenCB, 256 privCB, finiCB, ifCond, numThreads, pbKind, isCancellable)); 257 258 return bodyGenStatus; 259 } 260 261 /// Converts an OpenMP 'master' operation into LLVM IR using OpenMPIRBuilder. 262 static LogicalResult 263 convertOmpMaster(Operation &opInst, llvm::IRBuilderBase &builder, 264 LLVM::ModuleTranslation &moduleTranslation) { 265 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy; 266 // TODO: support error propagation in OpenMPIRBuilder and use it instead of 267 // relying on captured variables. 268 LogicalResult bodyGenStatus = success(); 269 270 auto bodyGenCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP, 271 llvm::BasicBlock &continuationBlock) { 272 // MasterOp has only one region associated with it. 273 auto ®ion = cast<omp::MasterOp>(opInst).getRegion(); 274 convertOmpOpRegions(region, "omp.master.region", *codeGenIP.getBlock(), 275 continuationBlock, builder, moduleTranslation, 276 bodyGenStatus); 277 }; 278 279 // TODO: Perform finalization actions for variables. This has to be 280 // called for variables which have destructors/finalizers. 281 auto finiCB = [&](InsertPointTy codeGenIP) {}; 282 283 llvm::OpenMPIRBuilder::LocationDescription ompLoc( 284 builder.saveIP(), builder.getCurrentDebugLocation()); 285 builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createMaster( 286 ompLoc, bodyGenCB, finiCB)); 287 return success(); 288 } 289 290 /// Converts an OpenMP 'critical' operation into LLVM IR using OpenMPIRBuilder. 291 static LogicalResult 292 convertOmpCritical(Operation &opInst, llvm::IRBuilderBase &builder, 293 LLVM::ModuleTranslation &moduleTranslation) { 294 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy; 295 auto criticalOp = cast<omp::CriticalOp>(opInst); 296 // TODO: support error propagation in OpenMPIRBuilder and use it instead of 297 // relying on captured variables. 298 LogicalResult bodyGenStatus = success(); 299 300 auto bodyGenCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP, 301 llvm::BasicBlock &continuationBlock) { 302 // CriticalOp has only one region associated with it. 303 auto ®ion = cast<omp::CriticalOp>(opInst).getRegion(); 304 convertOmpOpRegions(region, "omp.critical.region", *codeGenIP.getBlock(), 305 continuationBlock, builder, moduleTranslation, 306 bodyGenStatus); 307 }; 308 309 // TODO: Perform finalization actions for variables. This has to be 310 // called for variables which have destructors/finalizers. 311 auto finiCB = [&](InsertPointTy codeGenIP) {}; 312 313 llvm::OpenMPIRBuilder::LocationDescription ompLoc( 314 builder.saveIP(), builder.getCurrentDebugLocation()); 315 llvm::LLVMContext &llvmContext = moduleTranslation.getLLVMContext(); 316 llvm::Constant *hint = nullptr; 317 318 // If it has a name, it probably has a hint too. 319 if (criticalOp.nameAttr()) { 320 // The verifiers in OpenMP Dialect guarentee that all the pointers are 321 // non-null 322 auto symbolRef = criticalOp.nameAttr().cast<SymbolRefAttr>(); 323 auto criticalDeclareOp = 324 SymbolTable::lookupNearestSymbolFrom<omp::CriticalDeclareOp>(criticalOp, 325 symbolRef); 326 hint = llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvmContext), 327 static_cast<int>(criticalDeclareOp.hint())); 328 } 329 builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createCritical( 330 ompLoc, bodyGenCB, finiCB, criticalOp.name().getValueOr(""), hint)); 331 return success(); 332 } 333 334 /// Returns a reduction declaration that corresponds to the given reduction 335 /// operation in the given container. Currently only supports reductions inside 336 /// WsLoopOp but can be easily extended. 337 static omp::ReductionDeclareOp findReductionDecl(omp::WsLoopOp container, 338 omp::ReductionOp reduction) { 339 SymbolRefAttr reductionSymbol; 340 for (unsigned i = 0, e = container.getNumReductionVars(); i < e; ++i) { 341 if (container.reduction_vars()[i] != reduction.accumulator()) 342 continue; 343 reductionSymbol = (*container.reductions())[i].cast<SymbolRefAttr>(); 344 break; 345 } 346 assert(reductionSymbol && 347 "reduction operation must be associated with a declaration"); 348 349 return SymbolTable::lookupNearestSymbolFrom<omp::ReductionDeclareOp>( 350 container, reductionSymbol); 351 } 352 353 /// Populates `reductions` with reduction declarations used in the given loop. 354 static void 355 collectReductionDecls(omp::WsLoopOp loop, 356 SmallVectorImpl<omp::ReductionDeclareOp> &reductions) { 357 Optional<ArrayAttr> attr = loop.reductions(); 358 if (!attr) 359 return; 360 361 reductions.reserve(reductions.size() + loop.getNumReductionVars()); 362 for (auto symbolRef : attr->getAsRange<SymbolRefAttr>()) { 363 reductions.push_back( 364 SymbolTable::lookupNearestSymbolFrom<omp::ReductionDeclareOp>( 365 loop, symbolRef)); 366 } 367 } 368 369 /// Translates the blocks contained in the given region and appends them to at 370 /// the current insertion point of `builder`. The operations of the entry block 371 /// are appended to the current insertion block, which is not expected to have a 372 /// terminator. If set, `continuationBlockArgs` is populated with translated 373 /// values that correspond to the values omp.yield'ed from the region. 374 static LogicalResult inlineConvertOmpRegions( 375 Region ®ion, StringRef blockName, llvm::IRBuilderBase &builder, 376 LLVM::ModuleTranslation &moduleTranslation, 377 SmallVectorImpl<llvm::Value *> *continuationBlockArgs = nullptr) { 378 if (region.empty()) 379 return success(); 380 381 // Special case for single-block regions that don't create additional blocks: 382 // insert operations without creating additional blocks. 383 if (llvm::hasSingleElement(region)) { 384 moduleTranslation.mapBlock(®ion.front(), builder.GetInsertBlock()); 385 if (failed(moduleTranslation.convertBlock( 386 region.front(), /*ignoreArguments=*/true, builder))) 387 return failure(); 388 389 // The continuation arguments are simply the translated terminator operands. 390 if (continuationBlockArgs) 391 llvm::append_range( 392 *continuationBlockArgs, 393 moduleTranslation.lookupValues(region.front().back().getOperands())); 394 395 // Drop the mapping that is no longer necessary so that the same region can 396 // be processed multiple times. 397 moduleTranslation.forgetMapping(region); 398 return success(); 399 } 400 401 // Create the continuation block manually instead of calling splitBlock 402 // because the current insertion block may not have a terminator. 403 llvm::BasicBlock *continuationBlock = 404 llvm::BasicBlock::Create(builder.getContext(), blockName + ".cont", 405 builder.GetInsertBlock()->getParent(), 406 builder.GetInsertBlock()->getNextNode()); 407 builder.CreateBr(continuationBlock); 408 409 LogicalResult bodyGenStatus = success(); 410 SmallVector<llvm::PHINode *> phis; 411 convertOmpOpRegions(region, blockName, *builder.GetInsertBlock(), 412 *continuationBlock, builder, moduleTranslation, 413 bodyGenStatus, &phis); 414 if (failed(bodyGenStatus)) 415 return failure(); 416 if (continuationBlockArgs) 417 llvm::append_range(*continuationBlockArgs, phis); 418 builder.SetInsertPoint(continuationBlock, 419 continuationBlock->getFirstInsertionPt()); 420 return success(); 421 } 422 423 namespace { 424 /// Owning equivalents of OpenMPIRBuilder::(Atomic)ReductionGen that are used to 425 /// store lambdas with capture. 426 using OwningReductionGen = std::function<llvm::OpenMPIRBuilder::InsertPointTy( 427 llvm::OpenMPIRBuilder::InsertPointTy, llvm::Value *, llvm::Value *, 428 llvm::Value *&)>; 429 using OwningAtomicReductionGen = 430 std::function<llvm::OpenMPIRBuilder::InsertPointTy( 431 llvm::OpenMPIRBuilder::InsertPointTy, llvm::Type *, llvm::Value *, 432 llvm::Value *)>; 433 } // namespace 434 435 /// Create an OpenMPIRBuilder-compatible reduction generator for the given 436 /// reduction declaration. The generator uses `builder` but ignores its 437 /// insertion point. 438 static OwningReductionGen 439 makeReductionGen(omp::ReductionDeclareOp decl, llvm::IRBuilderBase &builder, 440 LLVM::ModuleTranslation &moduleTranslation) { 441 // The lambda is mutable because we need access to non-const methods of decl 442 // (which aren't actually mutating it), and we must capture decl by-value to 443 // avoid the dangling reference after the parent function returns. 444 OwningReductionGen gen = 445 [&, decl](llvm::OpenMPIRBuilder::InsertPointTy insertPoint, 446 llvm::Value *lhs, llvm::Value *rhs, 447 llvm::Value *&result) mutable { 448 Region &reductionRegion = decl.reductionRegion(); 449 moduleTranslation.mapValue(reductionRegion.front().getArgument(0), lhs); 450 moduleTranslation.mapValue(reductionRegion.front().getArgument(1), rhs); 451 builder.restoreIP(insertPoint); 452 SmallVector<llvm::Value *> phis; 453 if (failed(inlineConvertOmpRegions(reductionRegion, 454 "omp.reduction.nonatomic.body", 455 builder, moduleTranslation, &phis))) 456 return llvm::OpenMPIRBuilder::InsertPointTy(); 457 assert(phis.size() == 1); 458 result = phis[0]; 459 return builder.saveIP(); 460 }; 461 return gen; 462 } 463 464 /// Create an OpenMPIRBuilder-compatible atomic reduction generator for the 465 /// given reduction declaration. The generator uses `builder` but ignores its 466 /// insertion point. Returns null if there is no atomic region available in the 467 /// reduction declaration. 468 static OwningAtomicReductionGen 469 makeAtomicReductionGen(omp::ReductionDeclareOp decl, 470 llvm::IRBuilderBase &builder, 471 LLVM::ModuleTranslation &moduleTranslation) { 472 if (decl.atomicReductionRegion().empty()) 473 return OwningAtomicReductionGen(); 474 475 // The lambda is mutable because we need access to non-const methods of decl 476 // (which aren't actually mutating it), and we must capture decl by-value to 477 // avoid the dangling reference after the parent function returns. 478 OwningAtomicReductionGen atomicGen = 479 [&, decl](llvm::OpenMPIRBuilder::InsertPointTy insertPoint, llvm::Type *, 480 llvm::Value *lhs, llvm::Value *rhs) mutable { 481 Region &atomicRegion = decl.atomicReductionRegion(); 482 moduleTranslation.mapValue(atomicRegion.front().getArgument(0), lhs); 483 moduleTranslation.mapValue(atomicRegion.front().getArgument(1), rhs); 484 builder.restoreIP(insertPoint); 485 SmallVector<llvm::Value *> phis; 486 if (failed(inlineConvertOmpRegions(atomicRegion, 487 "omp.reduction.atomic.body", builder, 488 moduleTranslation, &phis))) 489 return llvm::OpenMPIRBuilder::InsertPointTy(); 490 assert(phis.empty()); 491 return builder.saveIP(); 492 }; 493 return atomicGen; 494 } 495 496 /// Converts an OpenMP 'ordered' operation into LLVM IR using OpenMPIRBuilder. 497 static LogicalResult 498 convertOmpOrdered(Operation &opInst, llvm::IRBuilderBase &builder, 499 LLVM::ModuleTranslation &moduleTranslation) { 500 auto orderedOp = cast<omp::OrderedOp>(opInst); 501 502 omp::ClauseDepend dependType = *orderedOp.depend_type_val(); 503 bool isDependSource = dependType == omp::ClauseDepend::dependsource; 504 unsigned numLoops = orderedOp.num_loops_val().getValue(); 505 SmallVector<llvm::Value *> vecValues = 506 moduleTranslation.lookupValues(orderedOp.depend_vec_vars()); 507 508 llvm::OpenMPIRBuilder::LocationDescription ompLoc( 509 builder.saveIP(), builder.getCurrentDebugLocation()); 510 size_t indexVecValues = 0; 511 while (indexVecValues < vecValues.size()) { 512 SmallVector<llvm::Value *> storeValues; 513 storeValues.reserve(numLoops); 514 for (unsigned i = 0; i < numLoops; i++) { 515 storeValues.push_back(vecValues[indexVecValues]); 516 indexVecValues++; 517 } 518 builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createOrderedDepend( 519 ompLoc, findAllocaInsertPoint(builder, moduleTranslation), numLoops, 520 storeValues, ".cnt.addr", isDependSource)); 521 } 522 return success(); 523 } 524 525 /// Converts an OpenMP 'ordered_region' operation into LLVM IR using 526 /// OpenMPIRBuilder. 527 static LogicalResult 528 convertOmpOrderedRegion(Operation &opInst, llvm::IRBuilderBase &builder, 529 LLVM::ModuleTranslation &moduleTranslation) { 530 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy; 531 auto orderedRegionOp = cast<omp::OrderedRegionOp>(opInst); 532 533 // TODO: The code generation for ordered simd directive is not supported yet. 534 if (orderedRegionOp.simd()) 535 return failure(); 536 537 // TODO: support error propagation in OpenMPIRBuilder and use it instead of 538 // relying on captured variables. 539 LogicalResult bodyGenStatus = success(); 540 541 auto bodyGenCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP, 542 llvm::BasicBlock &continuationBlock) { 543 // OrderedOp has only one region associated with it. 544 auto ®ion = cast<omp::OrderedRegionOp>(opInst).getRegion(); 545 convertOmpOpRegions(region, "omp.ordered.region", *codeGenIP.getBlock(), 546 continuationBlock, builder, moduleTranslation, 547 bodyGenStatus); 548 }; 549 550 // TODO: Perform finalization actions for variables. This has to be 551 // called for variables which have destructors/finalizers. 552 auto finiCB = [&](InsertPointTy codeGenIP) {}; 553 554 llvm::OpenMPIRBuilder::LocationDescription ompLoc( 555 builder.saveIP(), builder.getCurrentDebugLocation()); 556 builder.restoreIP( 557 moduleTranslation.getOpenMPBuilder()->createOrderedThreadsSimd( 558 ompLoc, bodyGenCB, finiCB, !orderedRegionOp.simd())); 559 return bodyGenStatus; 560 } 561 562 static LogicalResult 563 convertOmpSections(Operation &opInst, llvm::IRBuilderBase &builder, 564 LLVM::ModuleTranslation &moduleTranslation) { 565 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy; 566 using StorableBodyGenCallbackTy = 567 llvm::OpenMPIRBuilder::StorableBodyGenCallbackTy; 568 569 auto sectionsOp = cast<omp::SectionsOp>(opInst); 570 571 // TODO: Support the following clauses: private, firstprivate, lastprivate, 572 // reduction, allocate 573 if (!sectionsOp.private_vars().empty() || 574 !sectionsOp.firstprivate_vars().empty() || 575 !sectionsOp.lastprivate_vars().empty() || 576 !sectionsOp.reduction_vars().empty() || sectionsOp.reductions() || 577 !sectionsOp.allocate_vars().empty() || 578 !sectionsOp.allocators_vars().empty()) 579 return emitError(sectionsOp.getLoc()) 580 << "private, firstprivate, lastprivate, reduction and allocate " 581 "clauses are not supported for sections construct"; 582 583 LogicalResult bodyGenStatus = success(); 584 SmallVector<StorableBodyGenCallbackTy> sectionCBs; 585 586 for (Operation &op : *sectionsOp.region().begin()) { 587 auto sectionOp = dyn_cast<omp::SectionOp>(op); 588 if (!sectionOp) // omp.terminator 589 continue; 590 591 Region ®ion = sectionOp.region(); 592 auto sectionCB = [®ion, &builder, &moduleTranslation, &bodyGenStatus]( 593 InsertPointTy allocaIP, InsertPointTy codeGenIP, 594 llvm::BasicBlock &finiBB) { 595 builder.restoreIP(codeGenIP); 596 builder.CreateBr(&finiBB); 597 convertOmpOpRegions(region, "omp.section.region", *codeGenIP.getBlock(), 598 finiBB, builder, moduleTranslation, bodyGenStatus); 599 }; 600 sectionCBs.push_back(sectionCB); 601 } 602 603 // No sections within omp.sections operation - skip generation. This situation 604 // is only possible if there is only a terminator operation inside the 605 // sections operation 606 if (sectionCBs.empty()) 607 return success(); 608 609 assert(isa<omp::SectionOp>(*sectionsOp.region().op_begin())); 610 611 // TODO: Perform appropriate actions according to the data-sharing 612 // attribute (shared, private, firstprivate, ...) of variables. 613 // Currently defaults to shared. 614 auto privCB = [&](InsertPointTy, InsertPointTy codeGenIP, llvm::Value &, 615 llvm::Value &vPtr, 616 llvm::Value *&replacementValue) -> InsertPointTy { 617 replacementValue = &vPtr; 618 return codeGenIP; 619 }; 620 621 // TODO: Perform finalization actions for variables. This has to be 622 // called for variables which have destructors/finalizers. 623 auto finiCB = [&](InsertPointTy codeGenIP) {}; 624 625 llvm::OpenMPIRBuilder::LocationDescription ompLoc( 626 builder.saveIP(), builder.getCurrentDebugLocation()); 627 builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createSections( 628 ompLoc, findAllocaInsertPoint(builder, moduleTranslation), sectionCBs, 629 privCB, finiCB, false, sectionsOp.nowait())); 630 return bodyGenStatus; 631 } 632 633 /// Converts an OpenMP workshare loop into LLVM IR using OpenMPIRBuilder. 634 static LogicalResult 635 convertOmpWsLoop(Operation &opInst, llvm::IRBuilderBase &builder, 636 LLVM::ModuleTranslation &moduleTranslation) { 637 auto loop = cast<omp::WsLoopOp>(opInst); 638 // TODO: this should be in the op verifier instead. 639 if (loop.lowerBound().empty()) 640 return failure(); 641 642 // Static is the default. 643 auto schedule = 644 loop.schedule_val().getValueOr(omp::ClauseScheduleKind::Static); 645 646 // Find the loop configuration. 647 llvm::Value *step = moduleTranslation.lookupValue(loop.step()[0]); 648 llvm::Type *ivType = step->getType(); 649 llvm::Value *chunk = 650 loop.schedule_chunk_var() 651 ? moduleTranslation.lookupValue(loop.schedule_chunk_var()) 652 : llvm::ConstantInt::get(ivType, 1); 653 654 SmallVector<omp::ReductionDeclareOp> reductionDecls; 655 collectReductionDecls(loop, reductionDecls); 656 llvm::OpenMPIRBuilder::InsertPointTy allocaIP = 657 findAllocaInsertPoint(builder, moduleTranslation); 658 659 // Allocate space for privatized reduction variables. 660 SmallVector<llvm::Value *> privateReductionVariables; 661 DenseMap<Value, llvm::Value *> reductionVariableMap; 662 unsigned numReductions = loop.getNumReductionVars(); 663 privateReductionVariables.reserve(numReductions); 664 if (numReductions != 0) { 665 llvm::IRBuilderBase::InsertPointGuard guard(builder); 666 builder.restoreIP(allocaIP); 667 for (unsigned i = 0; i < numReductions; ++i) { 668 auto reductionType = 669 loop.reduction_vars()[i].getType().cast<LLVM::LLVMPointerType>(); 670 llvm::Value *var = builder.CreateAlloca( 671 moduleTranslation.convertType(reductionType.getElementType())); 672 privateReductionVariables.push_back(var); 673 reductionVariableMap.try_emplace(loop.reduction_vars()[i], var); 674 } 675 } 676 677 // Store the mapping between reduction variables and their private copies on 678 // ModuleTranslation stack. It can be then recovered when translating 679 // omp.reduce operations in a separate call. 680 LLVM::ModuleTranslation::SaveStack<OpenMPVarMappingStackFrame> mappingGuard( 681 moduleTranslation, reductionVariableMap); 682 683 // Before the loop, store the initial values of reductions into reduction 684 // variables. Although this could be done after allocas, we don't want to mess 685 // up with the alloca insertion point. 686 for (unsigned i = 0; i < numReductions; ++i) { 687 SmallVector<llvm::Value *> phis; 688 if (failed(inlineConvertOmpRegions(reductionDecls[i].initializerRegion(), 689 "omp.reduction.neutral", builder, 690 moduleTranslation, &phis))) 691 return failure(); 692 assert(phis.size() == 1 && "expected one value to be yielded from the " 693 "reduction neutral element declaration region"); 694 builder.CreateStore(phis[0], privateReductionVariables[i]); 695 } 696 697 // Set up the source location value for OpenMP runtime. 698 llvm::DISubprogram *subprogram = 699 builder.GetInsertBlock()->getParent()->getSubprogram(); 700 const llvm::DILocation *diLoc = 701 moduleTranslation.translateLoc(opInst.getLoc(), subprogram); 702 llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder.saveIP(), 703 llvm::DebugLoc(diLoc)); 704 705 // Generator of the canonical loop body. 706 // TODO: support error propagation in OpenMPIRBuilder and use it instead of 707 // relying on captured variables. 708 SmallVector<llvm::CanonicalLoopInfo *> loopInfos; 709 SmallVector<llvm::OpenMPIRBuilder::InsertPointTy> bodyInsertPoints; 710 LogicalResult bodyGenStatus = success(); 711 auto bodyGen = [&](llvm::OpenMPIRBuilder::InsertPointTy ip, llvm::Value *iv) { 712 // Make sure further conversions know about the induction variable. 713 moduleTranslation.mapValue( 714 loop.getRegion().front().getArgument(loopInfos.size()), iv); 715 716 // Capture the body insertion point for use in nested loops. BodyIP of the 717 // CanonicalLoopInfo always points to the beginning of the entry block of 718 // the body. 719 bodyInsertPoints.push_back(ip); 720 721 if (loopInfos.size() != loop.getNumLoops() - 1) 722 return; 723 724 // Convert the body of the loop. 725 llvm::BasicBlock *entryBlock = ip.getBlock(); 726 llvm::BasicBlock *exitBlock = 727 entryBlock->splitBasicBlock(ip.getPoint(), "omp.wsloop.exit"); 728 convertOmpOpRegions(loop.region(), "omp.wsloop.region", *entryBlock, 729 *exitBlock, builder, moduleTranslation, bodyGenStatus); 730 }; 731 732 // Delegate actual loop construction to the OpenMP IRBuilder. 733 // TODO: this currently assumes WsLoop is semantically similar to SCF loop, 734 // i.e. it has a positive step, uses signed integer semantics. Reconsider 735 // this code when WsLoop clearly supports more cases. 736 llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder(); 737 for (unsigned i = 0, e = loop.getNumLoops(); i < e; ++i) { 738 llvm::Value *lowerBound = 739 moduleTranslation.lookupValue(loop.lowerBound()[i]); 740 llvm::Value *upperBound = 741 moduleTranslation.lookupValue(loop.upperBound()[i]); 742 llvm::Value *step = moduleTranslation.lookupValue(loop.step()[i]); 743 744 // Make sure loop trip count are emitted in the preheader of the outermost 745 // loop at the latest so that they are all available for the new collapsed 746 // loop will be created below. 747 llvm::OpenMPIRBuilder::LocationDescription loc = ompLoc; 748 llvm::OpenMPIRBuilder::InsertPointTy computeIP = ompLoc.IP; 749 if (i != 0) { 750 loc = llvm::OpenMPIRBuilder::LocationDescription(bodyInsertPoints.back(), 751 llvm::DebugLoc(diLoc)); 752 computeIP = loopInfos.front()->getPreheaderIP(); 753 } 754 loopInfos.push_back(ompBuilder->createCanonicalLoop( 755 loc, bodyGen, lowerBound, upperBound, step, 756 /*IsSigned=*/true, loop.inclusive(), computeIP)); 757 758 if (failed(bodyGenStatus)) 759 return failure(); 760 } 761 762 // Collapse loops. Store the insertion point because LoopInfos may get 763 // invalidated. 764 llvm::IRBuilderBase::InsertPoint afterIP = loopInfos.front()->getAfterIP(); 765 llvm::CanonicalLoopInfo *loopInfo = 766 ompBuilder->collapseLoops(diLoc, loopInfos, {}); 767 768 allocaIP = findAllocaInsertPoint(builder, moduleTranslation); 769 770 bool isSimd = loop.simd_modifier(); 771 772 if (schedule == omp::ClauseScheduleKind::Static) { 773 ompBuilder->applyStaticWorkshareLoop(ompLoc.DL, loopInfo, allocaIP, 774 !loop.nowait(), chunk); 775 } else { 776 llvm::omp::OMPScheduleType schedType; 777 switch (schedule) { 778 case omp::ClauseScheduleKind::Dynamic: 779 schedType = llvm::omp::OMPScheduleType::DynamicChunked; 780 break; 781 case omp::ClauseScheduleKind::Guided: 782 if (isSimd) 783 schedType = llvm::omp::OMPScheduleType::GuidedSimd; 784 else 785 schedType = llvm::omp::OMPScheduleType::GuidedChunked; 786 break; 787 case omp::ClauseScheduleKind::Auto: 788 schedType = llvm::omp::OMPScheduleType::Auto; 789 break; 790 case omp::ClauseScheduleKind::Runtime: 791 if (isSimd) 792 schedType = llvm::omp::OMPScheduleType::RuntimeSimd; 793 else 794 schedType = llvm::omp::OMPScheduleType::Runtime; 795 break; 796 default: 797 llvm_unreachable("Unknown schedule value"); 798 break; 799 } 800 801 if (Optional<omp::ScheduleModifier> modifier = loop.schedule_modifier()) { 802 switch (*modifier) { 803 case omp::ScheduleModifier::monotonic: 804 schedType |= llvm::omp::OMPScheduleType::ModifierMonotonic; 805 break; 806 case omp::ScheduleModifier::nonmonotonic: 807 schedType |= llvm::omp::OMPScheduleType::ModifierNonmonotonic; 808 break; 809 default: 810 // Nothing to do here. 811 break; 812 } 813 } 814 afterIP = ompBuilder->applyDynamicWorkshareLoop( 815 ompLoc.DL, loopInfo, allocaIP, schedType, !loop.nowait(), chunk); 816 } 817 818 // Continue building IR after the loop. Note that the LoopInfo returned by 819 // `collapseLoops` points inside the outermost loop and is intended for 820 // potential further loop transformations. Use the insertion point stored 821 // before collapsing loops instead. 822 builder.restoreIP(afterIP); 823 824 // Process the reductions if required. 825 if (numReductions == 0) 826 return success(); 827 828 // Create the reduction generators. We need to own them here because 829 // ReductionInfo only accepts references to the generators. 830 SmallVector<OwningReductionGen> owningReductionGens; 831 SmallVector<OwningAtomicReductionGen> owningAtomicReductionGens; 832 for (unsigned i = 0; i < numReductions; ++i) { 833 owningReductionGens.push_back( 834 makeReductionGen(reductionDecls[i], builder, moduleTranslation)); 835 owningAtomicReductionGens.push_back( 836 makeAtomicReductionGen(reductionDecls[i], builder, moduleTranslation)); 837 } 838 839 // Collect the reduction information. 840 SmallVector<llvm::OpenMPIRBuilder::ReductionInfo> reductionInfos; 841 reductionInfos.reserve(numReductions); 842 for (unsigned i = 0; i < numReductions; ++i) { 843 llvm::OpenMPIRBuilder::AtomicReductionGenTy atomicGen = nullptr; 844 if (owningAtomicReductionGens[i]) 845 atomicGen = owningAtomicReductionGens[i]; 846 llvm::Value *variable = 847 moduleTranslation.lookupValue(loop.reduction_vars()[i]); 848 reductionInfos.push_back({variable->getType()->getPointerElementType(), 849 variable, privateReductionVariables[i], 850 owningReductionGens[i], atomicGen}); 851 } 852 853 // The call to createReductions below expects the block to have a 854 // terminator. Create an unreachable instruction to serve as terminator 855 // and remove it later. 856 llvm::UnreachableInst *tempTerminator = builder.CreateUnreachable(); 857 builder.SetInsertPoint(tempTerminator); 858 llvm::OpenMPIRBuilder::InsertPointTy contInsertPoint = 859 ompBuilder->createReductions(builder.saveIP(), allocaIP, reductionInfos, 860 loop.nowait()); 861 if (!contInsertPoint.getBlock()) 862 return loop->emitOpError() << "failed to convert reductions"; 863 auto nextInsertionPoint = 864 ompBuilder->createBarrier(contInsertPoint, llvm::omp::OMPD_for); 865 tempTerminator->eraseFromParent(); 866 builder.restoreIP(nextInsertionPoint); 867 868 return success(); 869 } 870 871 // Convert an Atomic Ordering attribute to llvm::AtomicOrdering. 872 llvm::AtomicOrdering 873 convertAtomicOrdering(Optional<omp::ClauseMemoryOrderKind> ao) { 874 if (!ao) 875 return llvm::AtomicOrdering::Monotonic; // Default Memory Ordering 876 877 switch (*ao) { 878 case omp::ClauseMemoryOrderKind::seq_cst: 879 return llvm::AtomicOrdering::SequentiallyConsistent; 880 case omp::ClauseMemoryOrderKind::acq_rel: 881 return llvm::AtomicOrdering::AcquireRelease; 882 case omp::ClauseMemoryOrderKind::acquire: 883 return llvm::AtomicOrdering::Acquire; 884 case omp::ClauseMemoryOrderKind::release: 885 return llvm::AtomicOrdering::Release; 886 case omp::ClauseMemoryOrderKind::relaxed: 887 return llvm::AtomicOrdering::Monotonic; 888 } 889 } 890 891 // Convert omp.atomic.read operation to LLVM IR. 892 static LogicalResult 893 convertOmpAtomicRead(Operation &opInst, llvm::IRBuilderBase &builder, 894 LLVM::ModuleTranslation &moduleTranslation) { 895 896 auto readOp = cast<omp::AtomicReadOp>(opInst); 897 llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder(); 898 899 // Set up the source location value for OpenMP runtime. 900 llvm::DISubprogram *subprogram = 901 builder.GetInsertBlock()->getParent()->getSubprogram(); 902 const llvm::DILocation *diLoc = 903 moduleTranslation.translateLoc(opInst.getLoc(), subprogram); 904 llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder.saveIP(), 905 llvm::DebugLoc(diLoc)); 906 llvm::AtomicOrdering AO = convertAtomicOrdering(readOp.memory_order()); 907 llvm::Value *x = moduleTranslation.lookupValue(readOp.x()); 908 llvm::Value *v = moduleTranslation.lookupValue(readOp.v()); 909 llvm::OpenMPIRBuilder::AtomicOpValue V = {v, false, false}; 910 llvm::OpenMPIRBuilder::AtomicOpValue X = {x, false, false}; 911 builder.restoreIP(ompBuilder->createAtomicRead(ompLoc, X, V, AO)); 912 return success(); 913 } 914 915 /// Converts an omp.atomic.write operation to LLVM IR. 916 static LogicalResult 917 convertOmpAtomicWrite(Operation &opInst, llvm::IRBuilderBase &builder, 918 LLVM::ModuleTranslation &moduleTranslation) { 919 auto writeOp = cast<omp::AtomicWriteOp>(opInst); 920 llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder(); 921 922 // Set up the source location value for OpenMP runtime. 923 llvm::DISubprogram *subprogram = 924 builder.GetInsertBlock()->getParent()->getSubprogram(); 925 const llvm::DILocation *diLoc = 926 moduleTranslation.translateLoc(opInst.getLoc(), subprogram); 927 llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder.saveIP(), 928 llvm::DebugLoc(diLoc)); 929 llvm::AtomicOrdering ao = convertAtomicOrdering(writeOp.memory_order()); 930 llvm::Value *expr = moduleTranslation.lookupValue(writeOp.value()); 931 llvm::Value *dest = moduleTranslation.lookupValue(writeOp.address()); 932 llvm::OpenMPIRBuilder::AtomicOpValue x = {dest, /*isSigned=*/false, 933 /*isVolatile=*/false}; 934 builder.restoreIP(ompBuilder->createAtomicWrite(ompLoc, x, expr, ao)); 935 return success(); 936 } 937 938 /// Converts an OpenMP reduction operation using OpenMPIRBuilder. Expects the 939 /// mapping between reduction variables and their private equivalents to have 940 /// been stored on the ModuleTranslation stack. Currently only supports 941 /// reduction within WsLoopOp, but can be easily extended. 942 static LogicalResult 943 convertOmpReductionOp(omp::ReductionOp reductionOp, 944 llvm::IRBuilderBase &builder, 945 LLVM::ModuleTranslation &moduleTranslation) { 946 // Find the declaration that corresponds to the reduction op. 947 auto reductionContainer = reductionOp->getParentOfType<omp::WsLoopOp>(); 948 omp::ReductionDeclareOp declaration = 949 findReductionDecl(reductionContainer, reductionOp); 950 assert(declaration && "could not find reduction declaration"); 951 952 // Retrieve the mapping between reduction variables and their private 953 // equivalents. 954 const DenseMap<Value, llvm::Value *> *reductionVariableMap = nullptr; 955 moduleTranslation.stackWalk<OpenMPVarMappingStackFrame>( 956 [&](const OpenMPVarMappingStackFrame &frame) { 957 reductionVariableMap = &frame.mapping; 958 return WalkResult::interrupt(); 959 }); 960 assert(reductionVariableMap && "couldn't find private reduction variables"); 961 962 // Translate the reduction operation by emitting the body of the corresponding 963 // reduction declaration. 964 Region &reductionRegion = declaration.reductionRegion(); 965 llvm::Value *privateReductionVar = 966 reductionVariableMap->lookup(reductionOp.accumulator()); 967 llvm::Value *reductionVal = builder.CreateLoad( 968 moduleTranslation.convertType(reductionOp.operand().getType()), 969 privateReductionVar); 970 971 moduleTranslation.mapValue(reductionRegion.front().getArgument(0), 972 reductionVal); 973 moduleTranslation.mapValue( 974 reductionRegion.front().getArgument(1), 975 moduleTranslation.lookupValue(reductionOp.operand())); 976 977 SmallVector<llvm::Value *> phis; 978 if (failed(inlineConvertOmpRegions(reductionRegion, "omp.reduction.body", 979 builder, moduleTranslation, &phis))) 980 return failure(); 981 assert(phis.size() == 1 && "expected one value to be yielded from " 982 "the reduction body declaration region"); 983 builder.CreateStore(phis[0], privateReductionVar); 984 return success(); 985 } 986 987 namespace { 988 989 /// Implementation of the dialect interface that converts operations belonging 990 /// to the OpenMP dialect to LLVM IR. 991 class OpenMPDialectLLVMIRTranslationInterface 992 : public LLVMTranslationDialectInterface { 993 public: 994 using LLVMTranslationDialectInterface::LLVMTranslationDialectInterface; 995 996 /// Translates the given operation to LLVM IR using the provided IR builder 997 /// and saving the state in `moduleTranslation`. 998 LogicalResult 999 convertOperation(Operation *op, llvm::IRBuilderBase &builder, 1000 LLVM::ModuleTranslation &moduleTranslation) const final; 1001 }; 1002 1003 } // namespace 1004 1005 /// Given an OpenMP MLIR operation, create the corresponding LLVM IR 1006 /// (including OpenMP runtime calls). 1007 LogicalResult OpenMPDialectLLVMIRTranslationInterface::convertOperation( 1008 Operation *op, llvm::IRBuilderBase &builder, 1009 LLVM::ModuleTranslation &moduleTranslation) const { 1010 1011 llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder(); 1012 1013 return llvm::TypeSwitch<Operation *, LogicalResult>(op) 1014 .Case([&](omp::BarrierOp) { 1015 ompBuilder->createBarrier(builder.saveIP(), llvm::omp::OMPD_barrier); 1016 return success(); 1017 }) 1018 .Case([&](omp::TaskwaitOp) { 1019 ompBuilder->createTaskwait(builder.saveIP()); 1020 return success(); 1021 }) 1022 .Case([&](omp::TaskyieldOp) { 1023 ompBuilder->createTaskyield(builder.saveIP()); 1024 return success(); 1025 }) 1026 .Case([&](omp::FlushOp) { 1027 // No support in Openmp runtime function (__kmpc_flush) to accept 1028 // the argument list. 1029 // OpenMP standard states the following: 1030 // "An implementation may implement a flush with a list by ignoring 1031 // the list, and treating it the same as a flush without a list." 1032 // 1033 // The argument list is discarded so that, flush with a list is treated 1034 // same as a flush without a list. 1035 ompBuilder->createFlush(builder.saveIP()); 1036 return success(); 1037 }) 1038 .Case([&](omp::ParallelOp op) { 1039 return convertOmpParallel(op, builder, moduleTranslation); 1040 }) 1041 .Case([&](omp::ReductionOp reductionOp) { 1042 return convertOmpReductionOp(reductionOp, builder, moduleTranslation); 1043 }) 1044 .Case([&](omp::MasterOp) { 1045 return convertOmpMaster(*op, builder, moduleTranslation); 1046 }) 1047 .Case([&](omp::CriticalOp) { 1048 return convertOmpCritical(*op, builder, moduleTranslation); 1049 }) 1050 .Case([&](omp::OrderedRegionOp) { 1051 return convertOmpOrderedRegion(*op, builder, moduleTranslation); 1052 }) 1053 .Case([&](omp::OrderedOp) { 1054 return convertOmpOrdered(*op, builder, moduleTranslation); 1055 }) 1056 .Case([&](omp::WsLoopOp) { 1057 return convertOmpWsLoop(*op, builder, moduleTranslation); 1058 }) 1059 .Case([&](omp::AtomicReadOp) { 1060 return convertOmpAtomicRead(*op, builder, moduleTranslation); 1061 }) 1062 .Case([&](omp::AtomicWriteOp) { 1063 return convertOmpAtomicWrite(*op, builder, moduleTranslation); 1064 }) 1065 .Case([&](omp::SectionsOp) { 1066 return convertOmpSections(*op, builder, moduleTranslation); 1067 }) 1068 .Case<omp::YieldOp, omp::TerminatorOp, omp::ReductionDeclareOp, 1069 omp::CriticalDeclareOp>([](auto op) { 1070 // `yield` and `terminator` can be just omitted. The block structure 1071 // was created in the region that handles their parent operation. 1072 // `reduction.declare` will be used by reductions and is not 1073 // converted directly, skip it. 1074 // `critical.declare` is only used to declare names of critical 1075 // sections which will be used by `critical` ops and hence can be 1076 // ignored for lowering. The OpenMP IRBuilder will create unique 1077 // name for critical section names. 1078 return success(); 1079 }) 1080 .Default([&](Operation *inst) { 1081 return inst->emitError("unsupported OpenMP operation: ") 1082 << inst->getName(); 1083 }); 1084 } 1085 1086 void mlir::registerOpenMPDialectTranslation(DialectRegistry ®istry) { 1087 registry.insert<omp::OpenMPDialect>(); 1088 registry.addDialectInterface<omp::OpenMPDialect, 1089 OpenMPDialectLLVMIRTranslationInterface>(); 1090 } 1091 1092 void mlir::registerOpenMPDialectTranslation(MLIRContext &context) { 1093 DialectRegistry registry; 1094 registerOpenMPDialectTranslation(registry); 1095 context.appendDialectRegistry(registry); 1096 } 1097