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