MLIR  14.0.0git
OpenMPToLLVMIRTranslation.cpp
Go to the documentation of this file.
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 //===----------------------------------------------------------------------===//
16 #include "mlir/IR/Operation.h"
17 #include "mlir/Support/LLVM.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
42  OpenMPVarMappingStackFrame> {
43 public:
44  explicit OpenMPVarMappingStackFrame(
45  const DenseMap<Value, llvm::Value *> &mapping)
46  : mapping(mapping) {}
47 
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 =
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.
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,
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.
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();
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::Value *, llvm::Value *)>;
419 } // namespace
420 
421 /// Create an OpenMPIRBuilder-compatible reduction generator for the given
422 /// reduction declaration. The generator uses `builder` but ignores its
423 /// insertion point.
424 static OwningReductionGen
425 makeReductionGen(omp::ReductionDeclareOp decl, llvm::IRBuilderBase &builder,
426  LLVM::ModuleTranslation &moduleTranslation) {
427  // The lambda is mutable because we need access to non-const methods of decl
428  // (which aren't actually mutating it), and we must capture decl by-value to
429  // avoid the dangling reference after the parent function returns.
430  OwningReductionGen gen =
431  [&, decl](llvm::OpenMPIRBuilder::InsertPointTy insertPoint,
432  llvm::Value *lhs, llvm::Value *rhs,
433  llvm::Value *&result) mutable {
434  Region &reductionRegion = decl.reductionRegion();
435  moduleTranslation.mapValue(reductionRegion.front().getArgument(0), lhs);
436  moduleTranslation.mapValue(reductionRegion.front().getArgument(1), rhs);
437  builder.restoreIP(insertPoint);
439  if (failed(inlineConvertOmpRegions(reductionRegion,
440  "omp.reduction.nonatomic.body",
441  builder, moduleTranslation, &phis)))
442  return llvm::OpenMPIRBuilder::InsertPointTy();
443  assert(phis.size() == 1);
444  result = phis[0];
445  return builder.saveIP();
446  };
447  return gen;
448 }
449 
450 /// Create an OpenMPIRBuilder-compatible atomic reduction generator for the
451 /// given reduction declaration. The generator uses `builder` but ignores its
452 /// insertion point. Returns null if there is no atomic region available in the
453 /// reduction declaration.
454 static OwningAtomicReductionGen
455 makeAtomicReductionGen(omp::ReductionDeclareOp decl,
456  llvm::IRBuilderBase &builder,
457  LLVM::ModuleTranslation &moduleTranslation) {
458  if (decl.atomicReductionRegion().empty())
459  return OwningAtomicReductionGen();
460 
461  // The lambda is mutable because we need access to non-const methods of decl
462  // (which aren't actually mutating it), and we must capture decl by-value to
463  // avoid the dangling reference after the parent function returns.
464  OwningAtomicReductionGen atomicGen =
465  [&, decl](llvm::OpenMPIRBuilder::InsertPointTy insertPoint,
466  llvm::Value *lhs, llvm::Value *rhs) mutable {
467  Region &atomicRegion = decl.atomicReductionRegion();
468  moduleTranslation.mapValue(atomicRegion.front().getArgument(0), lhs);
469  moduleTranslation.mapValue(atomicRegion.front().getArgument(1), rhs);
470  builder.restoreIP(insertPoint);
472  if (failed(inlineConvertOmpRegions(atomicRegion,
473  "omp.reduction.atomic.body", builder,
474  moduleTranslation, &phis)))
475  return llvm::OpenMPIRBuilder::InsertPointTy();
476  assert(phis.empty());
477  return builder.saveIP();
478  };
479  return atomicGen;
480 }
481 
482 /// Converts an OpenMP 'ordered' operation into LLVM IR using OpenMPIRBuilder.
483 static LogicalResult
484 convertOmpOrdered(Operation &opInst, llvm::IRBuilderBase &builder,
485  LLVM::ModuleTranslation &moduleTranslation) {
486  auto orderedOp = cast<omp::OrderedOp>(opInst);
487 
488  omp::ClauseDepend dependType =
489  *omp::symbolizeClauseDepend(orderedOp.depend_type_valAttr().getValue());
490  bool isDependSource = dependType == omp::ClauseDepend::dependsource;
491  unsigned numLoops = orderedOp.num_loops_val().getValue();
492  SmallVector<llvm::Value *> vecValues =
493  moduleTranslation.lookupValues(orderedOp.depend_vec_vars());
494 
495  llvm::OpenMPIRBuilder::LocationDescription ompLoc(
496  builder.saveIP(), builder.getCurrentDebugLocation());
497  size_t indexVecValues = 0;
498  while (indexVecValues < vecValues.size()) {
499  SmallVector<llvm::Value *> storeValues;
500  storeValues.reserve(numLoops);
501  for (unsigned i = 0; i < numLoops; i++) {
502  storeValues.push_back(vecValues[indexVecValues]);
503  indexVecValues++;
504  }
505  builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createOrderedDepend(
506  ompLoc, findAllocaInsertPoint(builder, moduleTranslation), numLoops,
507  storeValues, ".cnt.addr", isDependSource));
508  }
509  return success();
510 }
511 
512 /// Converts an OpenMP 'ordered_region' operation into LLVM IR using
513 /// OpenMPIRBuilder.
514 static LogicalResult
515 convertOmpOrderedRegion(Operation &opInst, llvm::IRBuilderBase &builder,
516  LLVM::ModuleTranslation &moduleTranslation) {
517  using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
518  auto orderedRegionOp = cast<omp::OrderedRegionOp>(opInst);
519 
520  // TODO: The code generation for ordered simd directive is not supported yet.
521  if (orderedRegionOp.simd())
522  return failure();
523 
524  // TODO: support error propagation in OpenMPIRBuilder and use it instead of
525  // relying on captured variables.
526  LogicalResult bodyGenStatus = success();
527 
528  auto bodyGenCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP,
529  llvm::BasicBlock &continuationBlock) {
530  // OrderedOp has only one region associated with it.
531  auto &region = cast<omp::OrderedRegionOp>(opInst).getRegion();
532  convertOmpOpRegions(region, "omp.ordered.region", *codeGenIP.getBlock(),
533  continuationBlock, builder, moduleTranslation,
534  bodyGenStatus);
535  };
536 
537  // TODO: Perform finalization actions for variables. This has to be
538  // called for variables which have destructors/finalizers.
539  auto finiCB = [&](InsertPointTy codeGenIP) {};
540 
541  llvm::OpenMPIRBuilder::LocationDescription ompLoc(
542  builder.saveIP(), builder.getCurrentDebugLocation());
543  builder.restoreIP(
544  moduleTranslation.getOpenMPBuilder()->createOrderedThreadsSimd(
545  ompLoc, bodyGenCB, finiCB, !orderedRegionOp.simd()));
546  return bodyGenStatus;
547 }
548 
549 /// Converts an OpenMP workshare loop into LLVM IR using OpenMPIRBuilder.
550 static LogicalResult
551 convertOmpWsLoop(Operation &opInst, llvm::IRBuilderBase &builder,
552  LLVM::ModuleTranslation &moduleTranslation) {
553  auto loop = cast<omp::WsLoopOp>(opInst);
554  // TODO: this should be in the op verifier instead.
555  if (loop.lowerBound().empty())
556  return failure();
557 
558  // Static is the default.
559  omp::ClauseScheduleKind schedule = omp::ClauseScheduleKind::Static;
560  if (loop.schedule_val().hasValue())
561  schedule =
562  *omp::symbolizeClauseScheduleKind(loop.schedule_val().getValue());
563 
564  // Find the loop configuration.
565  llvm::Value *step = moduleTranslation.lookupValue(loop.step()[0]);
566  llvm::Type *ivType = step->getType();
567  llvm::Value *chunk =
568  loop.schedule_chunk_var()
569  ? moduleTranslation.lookupValue(loop.schedule_chunk_var())
570  : llvm::ConstantInt::get(ivType, 1);
571 
573  collectReductionDecls(loop, reductionDecls);
574  llvm::OpenMPIRBuilder::InsertPointTy allocaIP =
575  findAllocaInsertPoint(builder, moduleTranslation);
576 
577  // Allocate space for privatized reduction variables.
578  SmallVector<llvm::Value *> privateReductionVariables;
579  DenseMap<Value, llvm::Value *> reductionVariableMap;
580  unsigned numReductions = loop.getNumReductionVars();
581  privateReductionVariables.reserve(numReductions);
582  if (numReductions != 0) {
583  llvm::IRBuilderBase::InsertPointGuard guard(builder);
584  builder.restoreIP(allocaIP);
585  for (unsigned i = 0; i < numReductions; ++i) {
586  auto reductionType =
587  loop.reduction_vars()[i].getType().cast<LLVM::LLVMPointerType>();
588  llvm::Value *var = builder.CreateAlloca(
589  moduleTranslation.convertType(reductionType.getElementType()));
590  privateReductionVariables.push_back(var);
591  reductionVariableMap.try_emplace(loop.reduction_vars()[i], var);
592  }
593  }
594 
595  // Store the mapping between reduction variables and their private copies on
596  // ModuleTranslation stack. It can be then recovered when translating
597  // omp.reduce operations in a separate call.
599  moduleTranslation, reductionVariableMap);
600 
601  // Before the loop, store the initial values of reductions into reduction
602  // variables. Although this could be done after allocas, we don't want to mess
603  // up with the alloca insertion point.
604  for (unsigned i = 0; i < numReductions; ++i) {
606  if (failed(inlineConvertOmpRegions(reductionDecls[i].initializerRegion(),
607  "omp.reduction.neutral", builder,
608  moduleTranslation, &phis)))
609  return failure();
610  assert(phis.size() == 1 && "expected one value to be yielded from the "
611  "reduction neutral element declaration region");
612  builder.CreateStore(phis[0], privateReductionVariables[i]);
613  }
614 
615  // Set up the source location value for OpenMP runtime.
616  llvm::DISubprogram *subprogram =
617  builder.GetInsertBlock()->getParent()->getSubprogram();
618  const llvm::DILocation *diLoc =
619  moduleTranslation.translateLoc(opInst.getLoc(), subprogram);
620  llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder.saveIP(),
621  llvm::DebugLoc(diLoc));
622 
623  // Generator of the canonical loop body.
624  // TODO: support error propagation in OpenMPIRBuilder and use it instead of
625  // relying on captured variables.
628  LogicalResult bodyGenStatus = success();
629  auto bodyGen = [&](llvm::OpenMPIRBuilder::InsertPointTy ip, llvm::Value *iv) {
630  // Make sure further conversions know about the induction variable.
631  moduleTranslation.mapValue(
632  loop.getRegion().front().getArgument(loopInfos.size()), iv);
633 
634  // Capture the body insertion point for use in nested loops. BodyIP of the
635  // CanonicalLoopInfo always points to the beginning of the entry block of
636  // the body.
637  bodyInsertPoints.push_back(ip);
638 
639  if (loopInfos.size() != loop.getNumLoops() - 1)
640  return;
641 
642  // Convert the body of the loop.
643  llvm::BasicBlock *entryBlock = ip.getBlock();
644  llvm::BasicBlock *exitBlock =
645  entryBlock->splitBasicBlock(ip.getPoint(), "omp.wsloop.exit");
646  convertOmpOpRegions(loop.region(), "omp.wsloop.region", *entryBlock,
647  *exitBlock, builder, moduleTranslation, bodyGenStatus);
648  };
649 
650  // Delegate actual loop construction to the OpenMP IRBuilder.
651  // TODO: this currently assumes WsLoop is semantically similar to SCF loop,
652  // i.e. it has a positive step, uses signed integer semantics. Reconsider
653  // this code when WsLoop clearly supports more cases.
654  llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
655  for (unsigned i = 0, e = loop.getNumLoops(); i < e; ++i) {
656  llvm::Value *lowerBound =
657  moduleTranslation.lookupValue(loop.lowerBound()[i]);
658  llvm::Value *upperBound =
659  moduleTranslation.lookupValue(loop.upperBound()[i]);
660  llvm::Value *step = moduleTranslation.lookupValue(loop.step()[i]);
661 
662  // Make sure loop trip count are emitted in the preheader of the outermost
663  // loop at the latest so that they are all available for the new collapsed
664  // loop will be created below.
665  llvm::OpenMPIRBuilder::LocationDescription loc = ompLoc;
666  llvm::OpenMPIRBuilder::InsertPointTy computeIP = ompLoc.IP;
667  if (i != 0) {
668  loc = llvm::OpenMPIRBuilder::LocationDescription(bodyInsertPoints.back(),
669  llvm::DebugLoc(diLoc));
670  computeIP = loopInfos.front()->getPreheaderIP();
671  }
672  loopInfos.push_back(ompBuilder->createCanonicalLoop(
673  loc, bodyGen, lowerBound, upperBound, step,
674  /*IsSigned=*/true, loop.inclusive(), computeIP));
675 
676  if (failed(bodyGenStatus))
677  return failure();
678  }
679 
680  // Collapse loops. Store the insertion point because LoopInfos may get
681  // invalidated.
682  llvm::IRBuilderBase::InsertPoint afterIP = loopInfos.front()->getAfterIP();
683  llvm::CanonicalLoopInfo *loopInfo =
684  ompBuilder->collapseLoops(diLoc, loopInfos, {});
685 
686  allocaIP = findAllocaInsertPoint(builder, moduleTranslation);
687 
688  bool isSimd = loop.simd_modifier();
689 
690  if (schedule == omp::ClauseScheduleKind::Static) {
691  ompBuilder->applyStaticWorkshareLoop(ompLoc.DL, loopInfo, allocaIP,
692  !loop.nowait(), chunk);
693  } else {
694  llvm::omp::OMPScheduleType schedType;
695  switch (schedule) {
696  case omp::ClauseScheduleKind::Dynamic:
697  schedType = llvm::omp::OMPScheduleType::DynamicChunked;
698  break;
699  case omp::ClauseScheduleKind::Guided:
700  if (isSimd)
701  schedType = llvm::omp::OMPScheduleType::GuidedSimd;
702  else
703  schedType = llvm::omp::OMPScheduleType::GuidedChunked;
704  break;
705  case omp::ClauseScheduleKind::Auto:
706  schedType = llvm::omp::OMPScheduleType::Auto;
707  break;
708  case omp::ClauseScheduleKind::Runtime:
709  if (isSimd)
710  schedType = llvm::omp::OMPScheduleType::RuntimeSimd;
711  else
712  schedType = llvm::omp::OMPScheduleType::Runtime;
713  break;
714  default:
715  llvm_unreachable("Unknown schedule value");
716  break;
717  }
718 
719  if (loop.schedule_modifier().hasValue()) {
720  omp::ScheduleModifier modifier =
721  *omp::symbolizeScheduleModifier(loop.schedule_modifier().getValue());
722  switch (modifier) {
723  case omp::ScheduleModifier::monotonic:
724  schedType |= llvm::omp::OMPScheduleType::ModifierMonotonic;
725  break;
726  case omp::ScheduleModifier::nonmonotonic:
727  schedType |= llvm::omp::OMPScheduleType::ModifierNonmonotonic;
728  break;
729  default:
730  // Nothing to do here.
731  break;
732  }
733  }
734  afterIP = ompBuilder->applyDynamicWorkshareLoop(
735  ompLoc.DL, loopInfo, allocaIP, schedType, !loop.nowait(), chunk);
736  }
737 
738  // Continue building IR after the loop. Note that the LoopInfo returned by
739  // `collapseLoops` points inside the outermost loop and is intended for
740  // potential further loop transformations. Use the insertion point stored
741  // before collapsing loops instead.
742  builder.restoreIP(afterIP);
743 
744  // Process the reductions if required.
745  if (numReductions == 0)
746  return success();
747 
748  // Create the reduction generators. We need to own them here because
749  // ReductionInfo only accepts references to the generators.
750  SmallVector<OwningReductionGen> owningReductionGens;
751  SmallVector<OwningAtomicReductionGen> owningAtomicReductionGens;
752  for (unsigned i = 0; i < numReductions; ++i) {
753  owningReductionGens.push_back(
754  makeReductionGen(reductionDecls[i], builder, moduleTranslation));
755  owningAtomicReductionGens.push_back(
756  makeAtomicReductionGen(reductionDecls[i], builder, moduleTranslation));
757  }
758 
759  // Collect the reduction information.
761  reductionInfos.reserve(numReductions);
762  for (unsigned i = 0; i < numReductions; ++i) {
763  llvm::OpenMPIRBuilder::AtomicReductionGenTy atomicGen = nullptr;
764  if (owningAtomicReductionGens[i])
765  atomicGen = owningAtomicReductionGens[i];
766  reductionInfos.push_back(
767  {moduleTranslation.lookupValue(loop.reduction_vars()[i]),
768  privateReductionVariables[i], owningReductionGens[i], atomicGen});
769  }
770 
771  // The call to createReductions below expects the block to have a
772  // terminator. Create an unreachable instruction to serve as terminator
773  // and remove it later.
774  llvm::UnreachableInst *tempTerminator = builder.CreateUnreachable();
775  builder.SetInsertPoint(tempTerminator);
776  llvm::OpenMPIRBuilder::InsertPointTy contInsertPoint =
777  ompBuilder->createReductions(builder.saveIP(), allocaIP, reductionInfos,
778  loop.nowait());
779  if (!contInsertPoint.getBlock())
780  return loop->emitOpError() << "failed to convert reductions";
781  auto nextInsertionPoint =
782  ompBuilder->createBarrier(contInsertPoint, llvm::omp::OMPD_for);
783  tempTerminator->eraseFromParent();
784  builder.restoreIP(nextInsertionPoint);
785 
786  return success();
787 }
788 
789 /// Converts an OpenMP reduction operation using OpenMPIRBuilder. Expects the
790 /// mapping between reduction variables and their private equivalents to have
791 /// been stored on the ModuleTranslation stack. Currently only supports
792 /// reduction within WsLoopOp, but can be easily extended.
793 static LogicalResult
794 convertOmpReductionOp(omp::ReductionOp reductionOp,
795  llvm::IRBuilderBase &builder,
796  LLVM::ModuleTranslation &moduleTranslation) {
797  // Find the declaration that corresponds to the reduction op.
798  auto reductionContainer = reductionOp->getParentOfType<omp::WsLoopOp>();
799  omp::ReductionDeclareOp declaration =
800  findReductionDecl(reductionContainer, reductionOp);
801  assert(declaration && "could not find reduction declaration");
802 
803  // Retrieve the mapping between reduction variables and their private
804  // equivalents.
805  const DenseMap<Value, llvm::Value *> *reductionVariableMap = nullptr;
806  moduleTranslation.stackWalk<OpenMPVarMappingStackFrame>(
807  [&](const OpenMPVarMappingStackFrame &frame) {
808  reductionVariableMap = &frame.mapping;
809  return WalkResult::interrupt();
810  });
811  assert(reductionVariableMap && "couldn't find private reduction variables");
812 
813  // Translate the reduction operation by emitting the body of the corresponding
814  // reduction declaration.
815  Region &reductionRegion = declaration.reductionRegion();
816  llvm::Value *privateReductionVar =
817  reductionVariableMap->lookup(reductionOp.accumulator());
818  llvm::Value *reductionVal = builder.CreateLoad(
819  moduleTranslation.convertType(reductionOp.operand().getType()),
820  privateReductionVar);
821 
822  moduleTranslation.mapValue(reductionRegion.front().getArgument(0),
823  reductionVal);
824  moduleTranslation.mapValue(
825  reductionRegion.front().getArgument(1),
826  moduleTranslation.lookupValue(reductionOp.operand()));
827 
829  if (failed(inlineConvertOmpRegions(reductionRegion, "omp.reduction.body",
830  builder, moduleTranslation, &phis)))
831  return failure();
832  assert(phis.size() == 1 && "expected one value to be yielded from "
833  "the reduction body declaration region");
834  builder.CreateStore(phis[0], privateReductionVar);
835  return success();
836 }
837 
838 namespace {
839 
840 /// Implementation of the dialect interface that converts operations belonging
841 /// to the OpenMP dialect to LLVM IR.
842 class OpenMPDialectLLVMIRTranslationInterface
844 public:
846 
847  /// Translates the given operation to LLVM IR using the provided IR builder
848  /// and saving the state in `moduleTranslation`.
850  convertOperation(Operation *op, llvm::IRBuilderBase &builder,
851  LLVM::ModuleTranslation &moduleTranslation) const final;
852 };
853 
854 } // end namespace
855 
856 /// Given an OpenMP MLIR operation, create the corresponding LLVM IR
857 /// (including OpenMP runtime calls).
858 LogicalResult OpenMPDialectLLVMIRTranslationInterface::convertOperation(
859  Operation *op, llvm::IRBuilderBase &builder,
860  LLVM::ModuleTranslation &moduleTranslation) const {
861 
862  llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
863 
865  .Case([&](omp::BarrierOp) {
866  ompBuilder->createBarrier(builder.saveIP(), llvm::omp::OMPD_barrier);
867  return success();
868  })
869  .Case([&](omp::TaskwaitOp) {
870  ompBuilder->createTaskwait(builder.saveIP());
871  return success();
872  })
873  .Case([&](omp::TaskyieldOp) {
874  ompBuilder->createTaskyield(builder.saveIP());
875  return success();
876  })
877  .Case([&](omp::FlushOp) {
878  // No support in Openmp runtime function (__kmpc_flush) to accept
879  // the argument list.
880  // OpenMP standard states the following:
881  // "An implementation may implement a flush with a list by ignoring
882  // the list, and treating it the same as a flush without a list."
883  //
884  // The argument list is discarded so that, flush with a list is treated
885  // same as a flush without a list.
886  ompBuilder->createFlush(builder.saveIP());
887  return success();
888  })
889  .Case([&](omp::ParallelOp) {
890  return convertOmpParallel(*op, builder, moduleTranslation);
891  })
892  .Case([&](omp::ReductionOp reductionOp) {
893  return convertOmpReductionOp(reductionOp, builder, moduleTranslation);
894  })
895  .Case([&](omp::MasterOp) {
896  return convertOmpMaster(*op, builder, moduleTranslation);
897  })
898  .Case([&](omp::CriticalOp) {
899  return convertOmpCritical(*op, builder, moduleTranslation);
900  })
901  .Case([&](omp::OrderedRegionOp) {
902  return convertOmpOrderedRegion(*op, builder, moduleTranslation);
903  })
904  .Case([&](omp::OrderedOp) {
905  return convertOmpOrdered(*op, builder, moduleTranslation);
906  })
907  .Case([&](omp::WsLoopOp) {
908  return convertOmpWsLoop(*op, builder, moduleTranslation);
909  })
910  .Case<omp::YieldOp, omp::TerminatorOp, omp::ReductionDeclareOp,
911  omp::CriticalDeclareOp>([](auto op) {
912  // `yield` and `terminator` can be just omitted. The block structure
913  // was created in the region that handles their parent operation.
914  // `reduction.declare` will be used by reductions and is not
915  // converted directly, skip it.
916  // `critical.declare` is only used to declare names of critical
917  // sections which will be used by `critical` ops and hence can be
918  // ignored for lowering. The OpenMP IRBuilder will create unique
919  // name for critical section names.
920  return success();
921  })
922  .Default([&](Operation *inst) {
923  return inst->emitError("unsupported OpenMP operation: ")
924  << inst->getName();
925  });
926 }
927 
929  registry.insert<omp::OpenMPDialect>();
930  registry.addDialectInterface<omp::OpenMPDialect,
931  OpenMPDialectLLVMIRTranslationInterface>();
932 }
933 
935  DialectRegistry registry;
937  context.appendDialectRegistry(registry);
938 }
Include the generated interface declarations.
This class contains a list of basic blocks and a link to the parent operation it is attached to...
Definition: Region.h:26
static omp::ReductionDeclareOp findReductionDecl(omp::WsLoopOp container, omp::ReductionOp reduction)
Returns a reduction declaration that corresponds to the given reduction operation in the given contai...
Operation is a basic unit of execution within MLIR.
Definition: Operation.h:28
Operation & back()
Definition: Block.h:144
operand_range getOperands()
Returns an iterator on the underlying Value&#39;s.
Definition: Operation.h:247
Block represents an ordered list of Operations.
Definition: Block.h:29
Block & front()
Definition: Region.h:65
const llvm::DILocation * translateLoc(Location loc, llvm::DILocalScope *scope)
Translates the given location.
llvm::Type * convertType(Type type)
Converts the type from MLIR LLVM dialect to LLVM.
bool wasInterrupted() const
Returns true if the walk was interrupted.
Definition: Visitors.h:55
Value getOperand(unsigned idx)
Definition: Operation.h:219
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value...
Definition: LogicalResult.h:72
static LogicalResult convertOmpWsLoop(Operation &opInst, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Converts an OpenMP workshare loop into LLVM IR using OpenMPIRBuilder.
static LogicalResult convertOmpOrdered(Operation &opInst, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Converts an OpenMP &#39;ordered&#39; operation into LLVM IR using OpenMPIRBuilder.
unsigned getNumOperands()
Definition: Operation.h:215
void appendDialectRegistry(const DialectRegistry &registry)
Append the contents of the given dialect registry to the registry associated with this context...
llvm::LLVMContext & getLLVMContext() const
Returns the LLVM context in which the IR is being constructed.
Concrete CRTP base class for ModuleTranslation stack frames.
static LogicalResult convertOmpOrderedRegion(Operation &opInst, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Converts an OpenMP &#39;ordered_region&#39; operation into LLVM IR using OpenMPIRBuilder. ...
SmallVector< llvm::Value * > lookupValues(ValueRange values)
Looks up remapped a list of remapped values.
LogicalResult convertBlock(Block &bb, bool ignoreArguments, llvm::IRBuilderBase &builder)
Translates the contents of the given block to LLVM IR using this translator.
llvm::BasicBlock * lookupBlock(Block *block) const
Finds an LLVM IR basic block that corresponds to the given MLIR block.
BlockArgument getArgument(unsigned i)
Definition: Block.h:121
static LogicalResult inlineConvertOmpRegions(Region &region, StringRef blockName, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation, SmallVectorImpl< llvm::Value *> *continuationBlockArgs=nullptr)
Translates the blocks contained in the given region and appends them to at the current insertion poin...
void addDialectInterface(TypeID interfaceTypeID, DialectInterfaceAllocatorFunction allocator)
Add an interface constructed with the given allocation function to the dialect provided as template p...
Definition: Dialect.h:347
void forgetMapping(Region &region)
Removes the mapping for blocks contained in the region and values defined in these blocks...
void mapBlock(Block *mlir, llvm::BasicBlock *llvm)
Stores the mapping between an MLIR block and LLVM IR basic block.
Implementation class for module translation.
llvm::OpenMPIRBuilder * getOpenMPBuilder()
Returns the OpenMP IR builder associated with the LLVM IR module being constructed.
static LogicalResult convertOmpReductionOp(omp::ReductionOp reductionOp, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Converts an OpenMP reduction operation using OpenMPIRBuilder.
static void convertOmpOpRegions(Region &region, StringRef blockName, llvm::BasicBlock &sourceBlock, llvm::BasicBlock &continuationBlock, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation, LogicalResult &bodyGenStatus, SmallVectorImpl< llvm::PHINode *> *continuationBlockPHIs=nullptr)
Converts the given region that appears within an OpenMP dialect operation to LLVM IR...
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
void mapValue(Value mlir, llvm::Value *llvm)
Stores the mapping between an MLIR value and its LLVM IR counterpart.
bool empty()
Definition: Region.h:60
Base class for dialect interfaces providing translation to LLVM IR.
RAII object calling stackPush/stackPop on construction/destruction.
static LogicalResult convertOmpCritical(Operation &opInst, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Converts an OpenMP &#39;critical&#39; operation into LLVM IR using OpenMPIRBuilder.
Location getLoc()
The source location the operation was defined or derived from.
Definition: Operation.h:106
static WalkResult interrupt()
Definition: Visitors.h:50
A utility result that is used to signal how to proceed with an ongoing walk:
Definition: Visitors.h:34
void registerOpenMPDialectTranslation(DialectRegistry &registry)
Register the OpenMP dialect and the translation from it to the LLVM IR in the given registry;...
llvm::Value * lookupValue(Value value) const
Finds an LLVM IR value corresponding to the given MLIR value.
static void collectReductionDecls(omp::WsLoopOp loop, SmallVectorImpl< omp::ReductionDeclareOp > &reductions)
Populates reductions with reduction declarations used in the given loop.
WalkResult stackWalk(llvm::function_ref< WalkResult(const T &)> callback) const
Calls callback for every ModuleTranslation stack frame of type T starting from the top of the stack...
void connectPHINodes(Region &region, const ModuleTranslation &state)
For all blocks in the region that were converted to LLVM IR using the given ModuleTranslation, connect the PHI nodes of the corresponding LLVM IR blocks to the results of preceding blocks.
static llvm::OpenMPIRBuilder::InsertPointTy findAllocaInsertPoint(llvm::IRBuilderBase &builder, const LLVM::ModuleTranslation &moduleTranslation)
Find the insertion point for allocas given the current insertion point for normal operations in the b...
static LogicalResult convertOmpParallel(Operation &opInst, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Converts the OpenMP parallel operation to LLVM IR.
SetVector< Block * > getTopologicallySortedBlocks(Region &region)
Get a topologically sorted list of blocks of the given region.
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
Definition: Dialect.h:282
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:55
static OwningAtomicReductionGen makeAtomicReductionGen(omp::ReductionDeclareOp decl, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Create an OpenMPIRBuilder-compatible atomic reduction generator for the given reduction declaration...
LLVM dialect pointer type.
Definition: LLVMTypes.h:158
static LogicalResult convertOmpMaster(Operation &opInst, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Converts an OpenMP &#39;master&#39; operation into LLVM IR using OpenMPIRBuilder.
OperationName getName()
The name of an operation is the key identifier for it.
Definition: Operation.h:57
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
Definition: Operation.cpp:231
static OwningReductionGen makeReductionGen(omp::ReductionDeclareOp decl, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Create an OpenMPIRBuilder-compatible reduction generator for the given reduction declaration.