MLIR  16.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/DebugInfoMetadata.h"
24 #include "llvm/IR/IRBuilder.h"
25 
26 using namespace mlir;
27 
28 namespace {
29 static llvm::omp::ScheduleKind
30 convertToScheduleKind(Optional<omp::ClauseScheduleKind> schedKind) {
31  if (!schedKind.has_value())
32  return llvm::omp::OMP_SCHEDULE_Default;
33  switch (schedKind.value()) {
34  case omp::ClauseScheduleKind::Static:
35  return llvm::omp::OMP_SCHEDULE_Static;
36  case omp::ClauseScheduleKind::Dynamic:
37  return llvm::omp::OMP_SCHEDULE_Dynamic;
38  case omp::ClauseScheduleKind::Guided:
39  return llvm::omp::OMP_SCHEDULE_Guided;
40  case omp::ClauseScheduleKind::Auto:
41  return llvm::omp::OMP_SCHEDULE_Auto;
43  return llvm::omp::OMP_SCHEDULE_Runtime;
44  }
45  llvm_unreachable("unhandled schedule clause argument");
46 }
47 
48 /// ModuleTranslation stack frame for OpenMP operations. This keeps track of the
49 /// insertion points for allocas.
50 class OpenMPAllocaStackFrame
51  : public LLVM::ModuleTranslation::StackFrameBase<OpenMPAllocaStackFrame> {
52 public:
53  MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(OpenMPAllocaStackFrame)
54 
55  explicit OpenMPAllocaStackFrame(llvm::OpenMPIRBuilder::InsertPointTy allocaIP)
56  : allocaInsertPoint(allocaIP) {}
57  llvm::OpenMPIRBuilder::InsertPointTy allocaInsertPoint;
58 };
59 
60 /// ModuleTranslation stack frame containing the partial mapping between MLIR
61 /// values and their LLVM IR equivalents.
62 class OpenMPVarMappingStackFrame
64  OpenMPVarMappingStackFrame> {
65 public:
66  MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(OpenMPVarMappingStackFrame)
67 
68  explicit OpenMPVarMappingStackFrame(
69  const DenseMap<Value, llvm::Value *> &mapping)
70  : mapping(mapping) {}
71 
73 };
74 } // namespace
75 
76 /// Find the insertion point for allocas given the current insertion point for
77 /// normal operations in the builder.
78 static llvm::OpenMPIRBuilder::InsertPointTy
79 findAllocaInsertPoint(llvm::IRBuilderBase &builder,
80  const LLVM::ModuleTranslation &moduleTranslation) {
81  // If there is an alloca insertion point on stack, i.e. we are in a nested
82  // operation and a specific point was provided by some surrounding operation,
83  // use it.
84  llvm::OpenMPIRBuilder::InsertPointTy allocaInsertPoint;
85  WalkResult walkResult = moduleTranslation.stackWalk<OpenMPAllocaStackFrame>(
86  [&](const OpenMPAllocaStackFrame &frame) {
87  allocaInsertPoint = frame.allocaInsertPoint;
88  return WalkResult::interrupt();
89  });
90  if (walkResult.wasInterrupted())
91  return allocaInsertPoint;
92 
93  // Otherwise, insert to the entry block of the surrounding function.
94  // If the current IRBuilder InsertPoint is the function's entry, it cannot
95  // also be used for alloca insertion which would result in insertion order
96  // confusion. Create a new BasicBlock for the Builder and use the entry block
97  // for the allocs.
98  // TODO: Create a dedicated alloca BasicBlock at function creation such that
99  // we do not need to move the current InertPoint here.
100  if (builder.GetInsertBlock() ==
101  &builder.GetInsertBlock()->getParent()->getEntryBlock()) {
102  assert(builder.GetInsertPoint() == builder.GetInsertBlock()->end() &&
103  "Assuming end of basic block");
104  llvm::BasicBlock *entryBB = llvm::BasicBlock::Create(
105  builder.getContext(), "entry", builder.GetInsertBlock()->getParent(),
106  builder.GetInsertBlock()->getNextNode());
107  builder.CreateBr(entryBB);
108  builder.SetInsertPoint(entryBB);
109  }
110 
111  llvm::BasicBlock &funcEntryBlock =
112  builder.GetInsertBlock()->getParent()->getEntryBlock();
113  return llvm::OpenMPIRBuilder::InsertPointTy(
114  &funcEntryBlock, funcEntryBlock.getFirstInsertionPt());
115 }
116 
117 /// Converts the given region that appears within an OpenMP dialect operation to
118 /// LLVM IR, creating a branch from the `sourceBlock` to the entry block of the
119 /// region, and a branch from any block with an successor-less OpenMP terminator
120 /// to `continuationBlock`. Populates `continuationBlockPHIs` with the PHI nodes
121 /// of the continuation block if provided.
122 static llvm::BasicBlock *convertOmpOpRegions(
123  Region &region, StringRef blockName, llvm::IRBuilderBase &builder,
124  LLVM::ModuleTranslation &moduleTranslation, LogicalResult &bodyGenStatus,
125  SmallVectorImpl<llvm::PHINode *> *continuationBlockPHIs = nullptr) {
126  llvm::BasicBlock *continuationBlock =
127  splitBB(builder, true, "omp.region.cont");
128  llvm::BasicBlock *sourceBlock = builder.GetInsertBlock();
129 
130  llvm::LLVMContext &llvmContext = builder.getContext();
131  for (Block &bb : region) {
132  llvm::BasicBlock *llvmBB = llvm::BasicBlock::Create(
133  llvmContext, blockName, builder.GetInsertBlock()->getParent(),
134  builder.GetInsertBlock()->getNextNode());
135  moduleTranslation.mapBlock(&bb, llvmBB);
136  }
137 
138  llvm::Instruction *sourceTerminator = sourceBlock->getTerminator();
139 
140  // Terminators (namely YieldOp) may be forwarding values to the region that
141  // need to be available in the continuation block. Collect the types of these
142  // operands in preparation of creating PHI nodes.
143  SmallVector<llvm::Type *> continuationBlockPHITypes;
144  bool operandsProcessed = false;
145  unsigned numYields = 0;
146  for (Block &bb : region.getBlocks()) {
147  if (omp::YieldOp yield = dyn_cast<omp::YieldOp>(bb.getTerminator())) {
148  if (!operandsProcessed) {
149  for (unsigned i = 0, e = yield->getNumOperands(); i < e; ++i) {
150  continuationBlockPHITypes.push_back(
151  moduleTranslation.convertType(yield->getOperand(i).getType()));
152  }
153  operandsProcessed = true;
154  } else {
155  assert(continuationBlockPHITypes.size() == yield->getNumOperands() &&
156  "mismatching number of values yielded from the region");
157  for (unsigned i = 0, e = yield->getNumOperands(); i < e; ++i) {
158  llvm::Type *operandType =
159  moduleTranslation.convertType(yield->getOperand(i).getType());
160  (void)operandType;
161  assert(continuationBlockPHITypes[i] == operandType &&
162  "values of mismatching types yielded from the region");
163  }
164  }
165  numYields++;
166  }
167  }
168 
169  // Insert PHI nodes in the continuation block for any values forwarded by the
170  // terminators in this region.
171  if (!continuationBlockPHITypes.empty())
172  assert(
173  continuationBlockPHIs &&
174  "expected continuation block PHIs if converted regions yield values");
175  if (continuationBlockPHIs) {
176  llvm::IRBuilderBase::InsertPointGuard guard(builder);
177  continuationBlockPHIs->reserve(continuationBlockPHITypes.size());
178  builder.SetInsertPoint(continuationBlock, continuationBlock->begin());
179  for (llvm::Type *ty : continuationBlockPHITypes)
180  continuationBlockPHIs->push_back(builder.CreatePHI(ty, numYields));
181  }
182 
183  // Convert blocks one by one in topological order to ensure
184  // defs are converted before uses.
185  SetVector<Block *> blocks =
187  for (Block *bb : blocks) {
188  llvm::BasicBlock *llvmBB = moduleTranslation.lookupBlock(bb);
189  // Retarget the branch of the entry block to the entry block of the
190  // converted region (regions are single-entry).
191  if (bb->isEntryBlock()) {
192  assert(sourceTerminator->getNumSuccessors() == 1 &&
193  "provided entry block has multiple successors");
194  assert(sourceTerminator->getSuccessor(0) == continuationBlock &&
195  "ContinuationBlock is not the successor of the entry block");
196  sourceTerminator->setSuccessor(0, llvmBB);
197  }
198 
199  llvm::IRBuilderBase::InsertPointGuard guard(builder);
200  if (failed(
201  moduleTranslation.convertBlock(*bb, bb->isEntryBlock(), builder))) {
202  bodyGenStatus = failure();
203  return continuationBlock;
204  }
205 
206  // Special handling for `omp.yield` and `omp.terminator` (we may have more
207  // than one): they return the control to the parent OpenMP dialect operation
208  // so replace them with the branch to the continuation block. We handle this
209  // here to avoid relying inter-function communication through the
210  // ModuleTranslation class to set up the correct insertion point. This is
211  // also consistent with MLIR's idiom of handling special region terminators
212  // in the same code that handles the region-owning operation.
213  Operation *terminator = bb->getTerminator();
214  if (isa<omp::TerminatorOp, omp::YieldOp>(terminator)) {
215  builder.CreateBr(continuationBlock);
216 
217  for (unsigned i = 0, e = terminator->getNumOperands(); i < e; ++i)
218  (*continuationBlockPHIs)[i]->addIncoming(
219  moduleTranslation.lookupValue(terminator->getOperand(i)), llvmBB);
220  }
221  }
222  // After all blocks have been traversed and values mapped, connect the PHI
223  // nodes to the results of preceding blocks.
224  LLVM::detail::connectPHINodes(region, moduleTranslation);
225 
226  // Remove the blocks and values defined in this region from the mapping since
227  // they are not visible outside of this region. This allows the same region to
228  // be converted several times, that is cloned, without clashes, and slightly
229  // speeds up the lookups.
230  moduleTranslation.forgetMapping(region);
231 
232  return continuationBlock;
233 }
234 
235 /// Convert ProcBindKind from MLIR-generated enum to LLVM enum.
236 static llvm::omp::ProcBindKind getProcBindKind(omp::ClauseProcBindKind kind) {
237  switch (kind) {
238  case omp::ClauseProcBindKind::Close:
239  return llvm::omp::ProcBindKind::OMP_PROC_BIND_close;
240  case omp::ClauseProcBindKind::Master:
241  return llvm::omp::ProcBindKind::OMP_PROC_BIND_master;
242  case omp::ClauseProcBindKind::Primary:
243  return llvm::omp::ProcBindKind::OMP_PROC_BIND_primary;
244  case omp::ClauseProcBindKind::Spread:
245  return llvm::omp::ProcBindKind::OMP_PROC_BIND_spread;
246  }
247  llvm_unreachable("Unknown ClauseProcBindKind kind");
248 }
249 
250 /// Converts the OpenMP parallel operation to LLVM IR.
251 static LogicalResult
252 convertOmpParallel(omp::ParallelOp opInst, llvm::IRBuilderBase &builder,
253  LLVM::ModuleTranslation &moduleTranslation) {
254  using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
255  // TODO: support error propagation in OpenMPIRBuilder and use it instead of
256  // relying on captured variables.
257  LogicalResult bodyGenStatus = success();
258 
259  auto bodyGenCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP) {
260  // Save the alloca insertion point on ModuleTranslation stack for use in
261  // nested regions.
263  moduleTranslation, allocaIP);
264 
265  // ParallelOp has only one region associated with it.
266  builder.restoreIP(codeGenIP);
267  convertOmpOpRegions(opInst.getRegion(), "omp.par.region", builder,
268  moduleTranslation, bodyGenStatus);
269  };
270 
271  // TODO: Perform appropriate actions according to the data-sharing
272  // attribute (shared, private, firstprivate, ...) of variables.
273  // Currently defaults to shared.
274  auto privCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP,
275  llvm::Value &, llvm::Value &vPtr,
276  llvm::Value *&replacementValue) -> InsertPointTy {
277  replacementValue = &vPtr;
278 
279  return codeGenIP;
280  };
281 
282  // TODO: Perform finalization actions for variables. This has to be
283  // called for variables which have destructors/finalizers.
284  auto finiCB = [&](InsertPointTy codeGenIP) {};
285 
286  llvm::Value *ifCond = nullptr;
287  if (auto ifExprVar = opInst.getIfExprVar())
288  ifCond = moduleTranslation.lookupValue(ifExprVar);
289  llvm::Value *numThreads = nullptr;
290  if (auto numThreadsVar = opInst.getNumThreadsVar())
291  numThreads = moduleTranslation.lookupValue(numThreadsVar);
292  auto pbKind = llvm::omp::OMP_PROC_BIND_default;
293  if (auto bind = opInst.getProcBindVal())
294  pbKind = getProcBindKind(*bind);
295  // TODO: Is the Parallel construct cancellable?
296  bool isCancellable = false;
297 
298  llvm::OpenMPIRBuilder::InsertPointTy allocaIP =
299  findAllocaInsertPoint(builder, moduleTranslation);
300  llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
301  builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createParallel(
302  ompLoc, allocaIP, bodyGenCB, privCB, finiCB, ifCond, numThreads, pbKind,
303  isCancellable));
304 
305  return bodyGenStatus;
306 }
307 
308 /// Converts an OpenMP 'master' operation into LLVM IR using OpenMPIRBuilder.
309 static LogicalResult
310 convertOmpMaster(Operation &opInst, llvm::IRBuilderBase &builder,
311  LLVM::ModuleTranslation &moduleTranslation) {
312  using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
313  // TODO: support error propagation in OpenMPIRBuilder and use it instead of
314  // relying on captured variables.
315  LogicalResult bodyGenStatus = success();
316 
317  auto bodyGenCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP) {
318  // MasterOp has only one region associated with it.
319  auto &region = cast<omp::MasterOp>(opInst).getRegion();
320  builder.restoreIP(codeGenIP);
321  convertOmpOpRegions(region, "omp.master.region", builder, moduleTranslation,
322  bodyGenStatus);
323  };
324 
325  // TODO: Perform finalization actions for variables. This has to be
326  // called for variables which have destructors/finalizers.
327  auto finiCB = [&](InsertPointTy codeGenIP) {};
328 
329  llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
330  builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createMaster(
331  ompLoc, bodyGenCB, finiCB));
332  return success();
333 }
334 
335 /// Converts an OpenMP 'critical' operation into LLVM IR using OpenMPIRBuilder.
336 static LogicalResult
337 convertOmpCritical(Operation &opInst, llvm::IRBuilderBase &builder,
338  LLVM::ModuleTranslation &moduleTranslation) {
339  using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
340  auto criticalOp = cast<omp::CriticalOp>(opInst);
341  // TODO: support error propagation in OpenMPIRBuilder and use it instead of
342  // relying on captured variables.
343  LogicalResult bodyGenStatus = success();
344 
345  auto bodyGenCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP) {
346  // CriticalOp has only one region associated with it.
347  auto &region = cast<omp::CriticalOp>(opInst).getRegion();
348  builder.restoreIP(codeGenIP);
349  convertOmpOpRegions(region, "omp.critical.region", builder,
350  moduleTranslation, bodyGenStatus);
351  };
352 
353  // TODO: Perform finalization actions for variables. This has to be
354  // called for variables which have destructors/finalizers.
355  auto finiCB = [&](InsertPointTy codeGenIP) {};
356 
357  llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
358  llvm::LLVMContext &llvmContext = moduleTranslation.getLLVMContext();
359  llvm::Constant *hint = nullptr;
360 
361  // If it has a name, it probably has a hint too.
362  if (criticalOp.getNameAttr()) {
363  // The verifiers in OpenMP Dialect guarentee that all the pointers are
364  // non-null
365  auto symbolRef = criticalOp.getNameAttr().cast<SymbolRefAttr>();
366  auto criticalDeclareOp =
367  SymbolTable::lookupNearestSymbolFrom<omp::CriticalDeclareOp>(criticalOp,
368  symbolRef);
369  hint = llvm::ConstantInt::get(
370  llvm::Type::getInt32Ty(llvmContext),
371  static_cast<int>(criticalDeclareOp.getHintVal()));
372  }
373  builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createCritical(
374  ompLoc, bodyGenCB, finiCB, criticalOp.getName().value_or(""), hint));
375  return success();
376 }
377 
378 /// Returns a reduction declaration that corresponds to the given reduction
379 /// operation in the given container. Currently only supports reductions inside
380 /// WsLoopOp but can be easily extended.
381 static omp::ReductionDeclareOp findReductionDecl(omp::WsLoopOp container,
382  omp::ReductionOp reduction) {
383  SymbolRefAttr reductionSymbol;
384  for (unsigned i = 0, e = container.getNumReductionVars(); i < e; ++i) {
385  if (container.getReductionVars()[i] != reduction.getAccumulator())
386  continue;
387  reductionSymbol = (*container.getReductions())[i].cast<SymbolRefAttr>();
388  break;
389  }
390  assert(reductionSymbol &&
391  "reduction operation must be associated with a declaration");
392 
393  return SymbolTable::lookupNearestSymbolFrom<omp::ReductionDeclareOp>(
394  container, reductionSymbol);
395 }
396 
397 /// Populates `reductions` with reduction declarations used in the given loop.
398 static void
399 collectReductionDecls(omp::WsLoopOp loop,
401  Optional<ArrayAttr> attr = loop.getReductions();
402  if (!attr)
403  return;
404 
405  reductions.reserve(reductions.size() + loop.getNumReductionVars());
406  for (auto symbolRef : attr->getAsRange<SymbolRefAttr>()) {
407  reductions.push_back(
408  SymbolTable::lookupNearestSymbolFrom<omp::ReductionDeclareOp>(
409  loop, symbolRef));
410  }
411 }
412 
413 /// Translates the blocks contained in the given region and appends them to at
414 /// the current insertion point of `builder`. The operations of the entry block
415 /// are appended to the current insertion block, which is not expected to have a
416 /// terminator. If set, `continuationBlockArgs` is populated with translated
417 /// values that correspond to the values omp.yield'ed from the region.
419  Region &region, StringRef blockName, llvm::IRBuilderBase &builder,
420  LLVM::ModuleTranslation &moduleTranslation,
421  SmallVectorImpl<llvm::Value *> *continuationBlockArgs = nullptr) {
422  if (region.empty())
423  return success();
424 
425  // Special case for single-block regions that don't create additional blocks:
426  // insert operations without creating additional blocks.
427  if (llvm::hasSingleElement(region)) {
428  moduleTranslation.mapBlock(&region.front(), builder.GetInsertBlock());
429  if (failed(moduleTranslation.convertBlock(
430  region.front(), /*ignoreArguments=*/true, builder)))
431  return failure();
432 
433  // The continuation arguments are simply the translated terminator operands.
434  if (continuationBlockArgs)
435  llvm::append_range(
436  *continuationBlockArgs,
437  moduleTranslation.lookupValues(region.front().back().getOperands()));
438 
439  // Drop the mapping that is no longer necessary so that the same region can
440  // be processed multiple times.
441  moduleTranslation.forgetMapping(region);
442  return success();
443  }
444 
445  LogicalResult bodyGenStatus = success();
447  llvm::BasicBlock *continuationBlock = convertOmpOpRegions(
448  region, blockName, builder, moduleTranslation, bodyGenStatus, &phis);
449  if (failed(bodyGenStatus))
450  return failure();
451  if (continuationBlockArgs)
452  llvm::append_range(*continuationBlockArgs, phis);
453  builder.SetInsertPoint(continuationBlock,
454  continuationBlock->getFirstInsertionPt());
455  return success();
456 }
457 
458 namespace {
459 /// Owning equivalents of OpenMPIRBuilder::(Atomic)ReductionGen that are used to
460 /// store lambdas with capture.
461 using OwningReductionGen = std::function<llvm::OpenMPIRBuilder::InsertPointTy(
462  llvm::OpenMPIRBuilder::InsertPointTy, llvm::Value *, llvm::Value *,
463  llvm::Value *&)>;
464 using OwningAtomicReductionGen =
465  std::function<llvm::OpenMPIRBuilder::InsertPointTy(
466  llvm::OpenMPIRBuilder::InsertPointTy, llvm::Type *, llvm::Value *,
467  llvm::Value *)>;
468 } // namespace
469 
470 /// Create an OpenMPIRBuilder-compatible reduction generator for the given
471 /// reduction declaration. The generator uses `builder` but ignores its
472 /// insertion point.
473 static OwningReductionGen
474 makeReductionGen(omp::ReductionDeclareOp decl, llvm::IRBuilderBase &builder,
475  LLVM::ModuleTranslation &moduleTranslation) {
476  // The lambda is mutable because we need access to non-const methods of decl
477  // (which aren't actually mutating it), and we must capture decl by-value to
478  // avoid the dangling reference after the parent function returns.
479  OwningReductionGen gen =
480  [&, decl](llvm::OpenMPIRBuilder::InsertPointTy insertPoint,
481  llvm::Value *lhs, llvm::Value *rhs,
482  llvm::Value *&result) mutable {
483  Region &reductionRegion = decl.getReductionRegion();
484  moduleTranslation.mapValue(reductionRegion.front().getArgument(0), lhs);
485  moduleTranslation.mapValue(reductionRegion.front().getArgument(1), rhs);
486  builder.restoreIP(insertPoint);
488  if (failed(inlineConvertOmpRegions(reductionRegion,
489  "omp.reduction.nonatomic.body",
490  builder, moduleTranslation, &phis)))
491  return llvm::OpenMPIRBuilder::InsertPointTy();
492  assert(phis.size() == 1);
493  result = phis[0];
494  return builder.saveIP();
495  };
496  return gen;
497 }
498 
499 /// Create an OpenMPIRBuilder-compatible atomic reduction generator for the
500 /// given reduction declaration. The generator uses `builder` but ignores its
501 /// insertion point. Returns null if there is no atomic region available in the
502 /// reduction declaration.
503 static OwningAtomicReductionGen
504 makeAtomicReductionGen(omp::ReductionDeclareOp decl,
505  llvm::IRBuilderBase &builder,
506  LLVM::ModuleTranslation &moduleTranslation) {
507  if (decl.getAtomicReductionRegion().empty())
508  return OwningAtomicReductionGen();
509 
510  // The lambda is mutable because we need access to non-const methods of decl
511  // (which aren't actually mutating it), and we must capture decl by-value to
512  // avoid the dangling reference after the parent function returns.
513  OwningAtomicReductionGen atomicGen =
514  [&, decl](llvm::OpenMPIRBuilder::InsertPointTy insertPoint, llvm::Type *,
515  llvm::Value *lhs, llvm::Value *rhs) mutable {
516  Region &atomicRegion = decl.getAtomicReductionRegion();
517  moduleTranslation.mapValue(atomicRegion.front().getArgument(0), lhs);
518  moduleTranslation.mapValue(atomicRegion.front().getArgument(1), rhs);
519  builder.restoreIP(insertPoint);
521  if (failed(inlineConvertOmpRegions(atomicRegion,
522  "omp.reduction.atomic.body", builder,
523  moduleTranslation, &phis)))
524  return llvm::OpenMPIRBuilder::InsertPointTy();
525  assert(phis.empty());
526  return builder.saveIP();
527  };
528  return atomicGen;
529 }
530 
531 /// Converts an OpenMP 'ordered' operation into LLVM IR using OpenMPIRBuilder.
532 static LogicalResult
533 convertOmpOrdered(Operation &opInst, llvm::IRBuilderBase &builder,
534  LLVM::ModuleTranslation &moduleTranslation) {
535  auto orderedOp = cast<omp::OrderedOp>(opInst);
536 
537  omp::ClauseDepend dependType = *orderedOp.getDependTypeVal();
538  bool isDependSource = dependType == omp::ClauseDepend::dependsource;
539  unsigned numLoops = *orderedOp.getNumLoopsVal();
540  SmallVector<llvm::Value *> vecValues =
541  moduleTranslation.lookupValues(orderedOp.getDependVecVars());
542 
543  size_t indexVecValues = 0;
544  while (indexVecValues < vecValues.size()) {
545  SmallVector<llvm::Value *> storeValues;
546  storeValues.reserve(numLoops);
547  for (unsigned i = 0; i < numLoops; i++) {
548  storeValues.push_back(vecValues[indexVecValues]);
549  indexVecValues++;
550  }
551  llvm::OpenMPIRBuilder::InsertPointTy allocaIP =
552  findAllocaInsertPoint(builder, moduleTranslation);
553  llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
554  builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createOrderedDepend(
555  ompLoc, allocaIP, numLoops, storeValues, ".cnt.addr", isDependSource));
556  }
557  return success();
558 }
559 
560 /// Converts an OpenMP 'ordered_region' operation into LLVM IR using
561 /// OpenMPIRBuilder.
562 static LogicalResult
563 convertOmpOrderedRegion(Operation &opInst, llvm::IRBuilderBase &builder,
564  LLVM::ModuleTranslation &moduleTranslation) {
565  using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
566  auto orderedRegionOp = cast<omp::OrderedRegionOp>(opInst);
567 
568  // TODO: The code generation for ordered simd directive is not supported yet.
569  if (orderedRegionOp.getSimd())
570  return failure();
571 
572  // TODO: support error propagation in OpenMPIRBuilder and use it instead of
573  // relying on captured variables.
574  LogicalResult bodyGenStatus = success();
575 
576  auto bodyGenCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP) {
577  // OrderedOp has only one region associated with it.
578  auto &region = cast<omp::OrderedRegionOp>(opInst).getRegion();
579  builder.restoreIP(codeGenIP);
580  convertOmpOpRegions(region, "omp.ordered.region", builder,
581  moduleTranslation, bodyGenStatus);
582  };
583 
584  // TODO: Perform finalization actions for variables. This has to be
585  // called for variables which have destructors/finalizers.
586  auto finiCB = [&](InsertPointTy codeGenIP) {};
587 
588  llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
589  builder.restoreIP(
590  moduleTranslation.getOpenMPBuilder()->createOrderedThreadsSimd(
591  ompLoc, bodyGenCB, finiCB, !orderedRegionOp.getSimd()));
592  return bodyGenStatus;
593 }
594 
595 static LogicalResult
596 convertOmpSections(Operation &opInst, llvm::IRBuilderBase &builder,
597  LLVM::ModuleTranslation &moduleTranslation) {
598  using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
599  using StorableBodyGenCallbackTy =
600  llvm::OpenMPIRBuilder::StorableBodyGenCallbackTy;
601 
602  auto sectionsOp = cast<omp::SectionsOp>(opInst);
603 
604  // TODO: Support the following clauses: private, firstprivate, lastprivate,
605  // reduction, allocate
606  if (!sectionsOp.getReductionVars().empty() || sectionsOp.getReductions() ||
607  !sectionsOp.getAllocateVars().empty() ||
608  !sectionsOp.getAllocatorsVars().empty())
609  return emitError(sectionsOp.getLoc())
610  << "reduction and allocate clauses are not supported for sections "
611  "construct";
612 
613  LogicalResult bodyGenStatus = success();
615 
616  for (Operation &op : *sectionsOp.getRegion().begin()) {
617  auto sectionOp = dyn_cast<omp::SectionOp>(op);
618  if (!sectionOp) // omp.terminator
619  continue;
620 
621  Region &region = sectionOp.getRegion();
622  auto sectionCB = [&region, &builder, &moduleTranslation, &bodyGenStatus](
623  InsertPointTy allocaIP, InsertPointTy codeGenIP) {
624  builder.restoreIP(codeGenIP);
625  convertOmpOpRegions(region, "omp.section.region", builder,
626  moduleTranslation, bodyGenStatus);
627  };
628  sectionCBs.push_back(sectionCB);
629  }
630 
631  // No sections within omp.sections operation - skip generation. This situation
632  // is only possible if there is only a terminator operation inside the
633  // sections operation
634  if (sectionCBs.empty())
635  return success();
636 
637  assert(isa<omp::SectionOp>(*sectionsOp.getRegion().op_begin()));
638 
639  // TODO: Perform appropriate actions according to the data-sharing
640  // attribute (shared, private, firstprivate, ...) of variables.
641  // Currently defaults to shared.
642  auto privCB = [&](InsertPointTy, InsertPointTy codeGenIP, llvm::Value &,
643  llvm::Value &vPtr,
644  llvm::Value *&replacementValue) -> InsertPointTy {
645  replacementValue = &vPtr;
646  return codeGenIP;
647  };
648 
649  // TODO: Perform finalization actions for variables. This has to be
650  // called for variables which have destructors/finalizers.
651  auto finiCB = [&](InsertPointTy codeGenIP) {};
652 
653  llvm::OpenMPIRBuilder::InsertPointTy allocaIP =
654  findAllocaInsertPoint(builder, moduleTranslation);
655  llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
656  builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createSections(
657  ompLoc, allocaIP, sectionCBs, privCB, finiCB, false,
658  sectionsOp.getNowait()));
659  return bodyGenStatus;
660 }
661 
662 /// Converts an OpenMP single construct into LLVM IR using OpenMPIRBuilder.
663 static LogicalResult
664 convertOmpSingle(omp::SingleOp &singleOp, llvm::IRBuilderBase &builder,
665  LLVM::ModuleTranslation &moduleTranslation) {
666  using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
667  llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
668  LogicalResult bodyGenStatus = success();
669  auto bodyCB = [&](InsertPointTy allocaIP, InsertPointTy codegenIP) {
670  builder.restoreIP(codegenIP);
671  convertOmpOpRegions(singleOp.getRegion(), "omp.single.region", builder,
672  moduleTranslation, bodyGenStatus);
673  };
674  auto finiCB = [&](InsertPointTy codeGenIP) {};
675  builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createSingle(
676  ompLoc, bodyCB, finiCB, singleOp.getNowait(), /*DidIt=*/nullptr));
677  return bodyGenStatus;
678 }
679 
680 /// Converts an OpenMP task construct into LLVM IR using OpenMPIRBuilder.
681 static LogicalResult
682 convertOmpTaskOp(omp::TaskOp taskOp, llvm::IRBuilderBase &builder,
683  LLVM::ModuleTranslation &moduleTranslation) {
684  using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
685  LogicalResult bodyGenStatus = success();
686  if (taskOp.getIfExpr() || taskOp.getFinalExpr() || taskOp.getUntiedAttr() ||
687  taskOp.getMergeableAttr() || taskOp.getInReductions() ||
688  taskOp.getPriority() || !taskOp.getAllocateVars().empty()) {
689  return taskOp.emitError("unhandled clauses for translation to LLVM IR");
690  }
691  auto bodyCB = [&](InsertPointTy allocaIP, InsertPointTy codegenIP) {
692  builder.restoreIP(codegenIP);
693  convertOmpOpRegions(taskOp.getRegion(), "omp.task.region", builder,
694  moduleTranslation, bodyGenStatus);
695  };
696  llvm::OpenMPIRBuilder::InsertPointTy allocaIP =
697  findAllocaInsertPoint(builder, moduleTranslation);
698  llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
699  builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createTask(
700  ompLoc, allocaIP, bodyCB, !taskOp.getUntied()));
701  return bodyGenStatus;
702 }
703 
704 /// Converts an OpenMP taskgroup construct into LLVM IR using OpenMPIRBuilder.
705 static LogicalResult
706 convertOmpTaskgroupOp(omp::TaskGroupOp tgOp, llvm::IRBuilderBase &builder,
707  LLVM::ModuleTranslation &moduleTranslation) {
708  using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
709  LogicalResult bodyGenStatus = success();
710  if (!tgOp.getTaskReductionVars().empty() || !tgOp.getAllocateVars().empty()) {
711  return tgOp.emitError("unhandled clauses for translation to LLVM IR");
712  }
713  auto bodyCB = [&](InsertPointTy allocaIP, InsertPointTy codegenIP) {
714  builder.restoreIP(codegenIP);
715  convertOmpOpRegions(tgOp.getRegion(), "omp.taskgroup.region", builder,
716  moduleTranslation, bodyGenStatus);
717  };
718  InsertPointTy allocaIP = findAllocaInsertPoint(builder, moduleTranslation);
719  llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
720  builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createTaskgroup(
721  ompLoc, allocaIP, bodyCB));
722  return bodyGenStatus;
723 }
724 
725 /// Converts an OpenMP workshare loop into LLVM IR using OpenMPIRBuilder.
726 static LogicalResult
727 convertOmpWsLoop(Operation &opInst, llvm::IRBuilderBase &builder,
728  LLVM::ModuleTranslation &moduleTranslation) {
729  auto loop = cast<omp::WsLoopOp>(opInst);
730  // TODO: this should be in the op verifier instead.
731  if (loop.getLowerBound().empty())
732  return failure();
733 
734  // Static is the default.
735  auto schedule =
736  loop.getScheduleVal().value_or(omp::ClauseScheduleKind::Static);
737 
738  // Find the loop configuration.
739  llvm::Value *step = moduleTranslation.lookupValue(loop.getStep()[0]);
740  llvm::Type *ivType = step->getType();
741  llvm::Value *chunk = nullptr;
742  if (loop.getScheduleChunkVar()) {
743  llvm::Value *chunkVar =
744  moduleTranslation.lookupValue(loop.getScheduleChunkVar());
745  chunk = builder.CreateSExtOrTrunc(chunkVar, ivType);
746  }
747 
749  collectReductionDecls(loop, reductionDecls);
750  llvm::OpenMPIRBuilder::InsertPointTy allocaIP =
751  findAllocaInsertPoint(builder, moduleTranslation);
752 
753  // Allocate space for privatized reduction variables.
754  SmallVector<llvm::Value *> privateReductionVariables;
755  DenseMap<Value, llvm::Value *> reductionVariableMap;
756  unsigned numReductions = loop.getNumReductionVars();
757  privateReductionVariables.reserve(numReductions);
758  if (numReductions != 0) {
759  llvm::IRBuilderBase::InsertPointGuard guard(builder);
760  builder.restoreIP(allocaIP);
761  for (unsigned i = 0; i < numReductions; ++i) {
762  auto reductionType =
763  loop.getReductionVars()[i].getType().cast<LLVM::LLVMPointerType>();
764  llvm::Value *var = builder.CreateAlloca(
765  moduleTranslation.convertType(reductionType.getElementType()));
766  privateReductionVariables.push_back(var);
767  reductionVariableMap.try_emplace(loop.getReductionVars()[i], var);
768  }
769  }
770 
771  // Store the mapping between reduction variables and their private copies on
772  // ModuleTranslation stack. It can be then recovered when translating
773  // omp.reduce operations in a separate call.
775  moduleTranslation, reductionVariableMap);
776 
777  // Before the loop, store the initial values of reductions into reduction
778  // variables. Although this could be done after allocas, we don't want to mess
779  // up with the alloca insertion point.
780  for (unsigned i = 0; i < numReductions; ++i) {
782  if (failed(inlineConvertOmpRegions(reductionDecls[i].getInitializerRegion(),
783  "omp.reduction.neutral", builder,
784  moduleTranslation, &phis)))
785  return failure();
786  assert(phis.size() == 1 && "expected one value to be yielded from the "
787  "reduction neutral element declaration region");
788  builder.CreateStore(phis[0], privateReductionVariables[i]);
789  }
790 
791  // Set up the source location value for OpenMP runtime.
792  llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
793 
794  // Generator of the canonical loop body.
795  // TODO: support error propagation in OpenMPIRBuilder and use it instead of
796  // relying on captured variables.
799  LogicalResult bodyGenStatus = success();
800  auto bodyGen = [&](llvm::OpenMPIRBuilder::InsertPointTy ip, llvm::Value *iv) {
801  // Make sure further conversions know about the induction variable.
802  moduleTranslation.mapValue(
803  loop.getRegion().front().getArgument(loopInfos.size()), iv);
804 
805  // Capture the body insertion point for use in nested loops. BodyIP of the
806  // CanonicalLoopInfo always points to the beginning of the entry block of
807  // the body.
808  bodyInsertPoints.push_back(ip);
809 
810  if (loopInfos.size() != loop.getNumLoops() - 1)
811  return;
812 
813  // Convert the body of the loop.
814  builder.restoreIP(ip);
815  convertOmpOpRegions(loop.getRegion(), "omp.wsloop.region", builder,
816  moduleTranslation, bodyGenStatus);
817  };
818 
819  // Delegate actual loop construction to the OpenMP IRBuilder.
820  // TODO: this currently assumes WsLoop is semantically similar to SCF loop,
821  // i.e. it has a positive step, uses signed integer semantics. Reconsider
822  // this code when WsLoop clearly supports more cases.
823  llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
824  for (unsigned i = 0, e = loop.getNumLoops(); i < e; ++i) {
825  llvm::Value *lowerBound =
826  moduleTranslation.lookupValue(loop.getLowerBound()[i]);
827  llvm::Value *upperBound =
828  moduleTranslation.lookupValue(loop.getUpperBound()[i]);
829  llvm::Value *step = moduleTranslation.lookupValue(loop.getStep()[i]);
830 
831  // Make sure loop trip count are emitted in the preheader of the outermost
832  // loop at the latest so that they are all available for the new collapsed
833  // loop will be created below.
834  llvm::OpenMPIRBuilder::LocationDescription loc = ompLoc;
835  llvm::OpenMPIRBuilder::InsertPointTy computeIP = ompLoc.IP;
836  if (i != 0) {
837  loc = llvm::OpenMPIRBuilder::LocationDescription(bodyInsertPoints.back());
838  computeIP = loopInfos.front()->getPreheaderIP();
839  }
840  loopInfos.push_back(ompBuilder->createCanonicalLoop(
841  loc, bodyGen, lowerBound, upperBound, step,
842  /*IsSigned=*/true, loop.getInclusive(), computeIP));
843 
844  if (failed(bodyGenStatus))
845  return failure();
846  }
847 
848  // Collapse loops. Store the insertion point because LoopInfos may get
849  // invalidated.
850  llvm::IRBuilderBase::InsertPoint afterIP = loopInfos.front()->getAfterIP();
851  llvm::CanonicalLoopInfo *loopInfo =
852  ompBuilder->collapseLoops(ompLoc.DL, loopInfos, {});
853 
854  allocaIP = findAllocaInsertPoint(builder, moduleTranslation);
855 
856  // TODO: Handle doacross loops when the ordered clause has a parameter.
857  bool isOrdered = loop.getOrderedVal().has_value();
858  Optional<omp::ScheduleModifier> scheduleModifier = loop.getScheduleModifier();
859  bool isSimd = loop.getSimdModifier();
860 
861  ompBuilder->applyWorkshareLoop(
862  ompLoc.DL, loopInfo, allocaIP, !loop.getNowait(),
863  convertToScheduleKind(schedule), chunk, isSimd,
864  scheduleModifier == omp::ScheduleModifier::monotonic,
865  scheduleModifier == omp::ScheduleModifier::nonmonotonic, isOrdered);
866 
867  // Continue building IR after the loop. Note that the LoopInfo returned by
868  // `collapseLoops` points inside the outermost loop and is intended for
869  // potential further loop transformations. Use the insertion point stored
870  // before collapsing loops instead.
871  builder.restoreIP(afterIP);
872 
873  // Process the reductions if required.
874  if (numReductions == 0)
875  return success();
876 
877  // Create the reduction generators. We need to own them here because
878  // ReductionInfo only accepts references to the generators.
879  SmallVector<OwningReductionGen> owningReductionGens;
880  SmallVector<OwningAtomicReductionGen> owningAtomicReductionGens;
881  for (unsigned i = 0; i < numReductions; ++i) {
882  owningReductionGens.push_back(
883  makeReductionGen(reductionDecls[i], builder, moduleTranslation));
884  owningAtomicReductionGens.push_back(
885  makeAtomicReductionGen(reductionDecls[i], builder, moduleTranslation));
886  }
887 
888  // Collect the reduction information.
890  reductionInfos.reserve(numReductions);
891  for (unsigned i = 0; i < numReductions; ++i) {
892  llvm::OpenMPIRBuilder::AtomicReductionGenTy atomicGen = nullptr;
893  if (owningAtomicReductionGens[i])
894  atomicGen = owningAtomicReductionGens[i];
895  auto reductionType =
896  loop.getReductionVars()[i].getType().cast<LLVM::LLVMPointerType>();
897  llvm::Value *variable =
898  moduleTranslation.lookupValue(loop.getReductionVars()[i]);
899  reductionInfos.push_back(
900  {moduleTranslation.convertType(reductionType.getElementType()),
901  variable, privateReductionVariables[i], owningReductionGens[i],
902  atomicGen});
903  }
904 
905  // The call to createReductions below expects the block to have a
906  // terminator. Create an unreachable instruction to serve as terminator
907  // and remove it later.
908  llvm::UnreachableInst *tempTerminator = builder.CreateUnreachable();
909  builder.SetInsertPoint(tempTerminator);
910  llvm::OpenMPIRBuilder::InsertPointTy contInsertPoint =
911  ompBuilder->createReductions(builder.saveIP(), allocaIP, reductionInfos,
912  loop.getNowait());
913  if (!contInsertPoint.getBlock())
914  return loop->emitOpError() << "failed to convert reductions";
915  auto nextInsertionPoint =
916  ompBuilder->createBarrier(contInsertPoint, llvm::omp::OMPD_for);
917  tempTerminator->eraseFromParent();
918  builder.restoreIP(nextInsertionPoint);
919 
920  return success();
921 }
922 
923 /// Converts an OpenMP simd loop into LLVM IR using OpenMPIRBuilder.
924 static LogicalResult
925 convertOmpSimdLoop(Operation &opInst, llvm::IRBuilderBase &builder,
926  LLVM::ModuleTranslation &moduleTranslation) {
927  auto loop = cast<omp::SimdLoopOp>(opInst);
928 
929  llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
930 
931  // Generator of the canonical loop body.
932  // TODO: support error propagation in OpenMPIRBuilder and use it instead of
933  // relying on captured variables.
936  LogicalResult bodyGenStatus = success();
937  auto bodyGen = [&](llvm::OpenMPIRBuilder::InsertPointTy ip, llvm::Value *iv) {
938  // Make sure further conversions know about the induction variable.
939  moduleTranslation.mapValue(
940  loop.getRegion().front().getArgument(loopInfos.size()), iv);
941 
942  // Capture the body insertion point for use in nested loops. BodyIP of the
943  // CanonicalLoopInfo always points to the beginning of the entry block of
944  // the body.
945  bodyInsertPoints.push_back(ip);
946 
947  if (loopInfos.size() != loop.getNumLoops() - 1)
948  return;
949 
950  // Convert the body of the loop.
951  builder.restoreIP(ip);
952  convertOmpOpRegions(loop.getRegion(), "omp.simdloop.region", builder,
953  moduleTranslation, bodyGenStatus);
954  };
955 
956  // Delegate actual loop construction to the OpenMP IRBuilder.
957  // TODO: this currently assumes SimdLoop is semantically similar to SCF loop,
958  // i.e. it has a positive step, uses signed integer semantics. Reconsider
959  // this code when SimdLoop clearly supports more cases.
960  llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
961  for (unsigned i = 0, e = loop.getNumLoops(); i < e; ++i) {
962  llvm::Value *lowerBound =
963  moduleTranslation.lookupValue(loop.getLowerBound()[i]);
964  llvm::Value *upperBound =
965  moduleTranslation.lookupValue(loop.getUpperBound()[i]);
966  llvm::Value *step = moduleTranslation.lookupValue(loop.getStep()[i]);
967 
968  // Make sure loop trip count are emitted in the preheader of the outermost
969  // loop at the latest so that they are all available for the new collapsed
970  // loop will be created below.
971  llvm::OpenMPIRBuilder::LocationDescription loc = ompLoc;
972  llvm::OpenMPIRBuilder::InsertPointTy computeIP = ompLoc.IP;
973  if (i != 0) {
974  loc = llvm::OpenMPIRBuilder::LocationDescription(bodyInsertPoints.back(),
975  ompLoc.DL);
976  computeIP = loopInfos.front()->getPreheaderIP();
977  }
978  loopInfos.push_back(ompBuilder->createCanonicalLoop(
979  loc, bodyGen, lowerBound, upperBound, step,
980  /*IsSigned=*/true, /*Inclusive=*/true, computeIP));
981 
982  if (failed(bodyGenStatus))
983  return failure();
984  }
985 
986  // Collapse loops.
987  llvm::IRBuilderBase::InsertPoint afterIP = loopInfos.front()->getAfterIP();
988  llvm::CanonicalLoopInfo *loopInfo =
989  ompBuilder->collapseLoops(ompLoc.DL, loopInfos, {});
990 
991  llvm::ConstantInt *simdlen = nullptr;
992  if (llvm::Optional<uint64_t> simdlenVar = loop.getSimdlen())
993  simdlen = builder.getInt64(simdlenVar.value());
994 
995  llvm::ConstantInt *safelen = nullptr;
996  if (llvm::Optional<uint64_t> safelenVar = loop.getSafelen())
997  safelen = builder.getInt64(safelenVar.value());
998 
999  llvm::MapVector<llvm::Value *, llvm::Value *> alignedVars;
1000  ompBuilder->applySimd(
1001  loopInfo, alignedVars,
1002  loop.getIfExpr() ? moduleTranslation.lookupValue(loop.getIfExpr())
1003  : nullptr,
1004  llvm::omp::OrderKind::OMP_ORDER_unknown, simdlen, safelen);
1005 
1006  builder.restoreIP(afterIP);
1007  return success();
1008 }
1009 
1010 /// Convert an Atomic Ordering attribute to llvm::AtomicOrdering.
1011 llvm::AtomicOrdering
1013  if (!ao)
1014  return llvm::AtomicOrdering::Monotonic; // Default Memory Ordering
1015 
1016  switch (*ao) {
1017  case omp::ClauseMemoryOrderKind::Seq_cst:
1018  return llvm::AtomicOrdering::SequentiallyConsistent;
1019  case omp::ClauseMemoryOrderKind::Acq_rel:
1020  return llvm::AtomicOrdering::AcquireRelease;
1021  case omp::ClauseMemoryOrderKind::Acquire:
1022  return llvm::AtomicOrdering::Acquire;
1023  case omp::ClauseMemoryOrderKind::Release:
1024  return llvm::AtomicOrdering::Release;
1025  case omp::ClauseMemoryOrderKind::Relaxed:
1026  return llvm::AtomicOrdering::Monotonic;
1027  }
1028  llvm_unreachable("Unknown ClauseMemoryOrderKind kind");
1029 }
1030 
1031 /// Convert omp.atomic.read operation to LLVM IR.
1032 static LogicalResult
1033 convertOmpAtomicRead(Operation &opInst, llvm::IRBuilderBase &builder,
1034  LLVM::ModuleTranslation &moduleTranslation) {
1035 
1036  auto readOp = cast<omp::AtomicReadOp>(opInst);
1037  llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
1038 
1039  llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
1040 
1041  llvm::AtomicOrdering AO = convertAtomicOrdering(readOp.getMemoryOrderVal());
1042  llvm::Value *x = moduleTranslation.lookupValue(readOp.getX());
1043  Type xTy =
1044  readOp.getX().getType().cast<omp::PointerLikeType>().getElementType();
1045  llvm::Value *v = moduleTranslation.lookupValue(readOp.getV());
1046  Type vTy =
1047  readOp.getV().getType().cast<omp::PointerLikeType>().getElementType();
1048  llvm::OpenMPIRBuilder::AtomicOpValue V = {
1049  v, moduleTranslation.convertType(vTy), false, false};
1050  llvm::OpenMPIRBuilder::AtomicOpValue X = {
1051  x, moduleTranslation.convertType(xTy), false, false};
1052  builder.restoreIP(ompBuilder->createAtomicRead(ompLoc, X, V, AO));
1053  return success();
1054 }
1055 
1056 /// Converts an omp.atomic.write operation to LLVM IR.
1057 static LogicalResult
1058 convertOmpAtomicWrite(Operation &opInst, llvm::IRBuilderBase &builder,
1059  LLVM::ModuleTranslation &moduleTranslation) {
1060  auto writeOp = cast<omp::AtomicWriteOp>(opInst);
1061  llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
1062 
1063  llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
1064  llvm::AtomicOrdering ao = convertAtomicOrdering(writeOp.getMemoryOrderVal());
1065  llvm::Value *expr = moduleTranslation.lookupValue(writeOp.getValue());
1066  llvm::Value *dest = moduleTranslation.lookupValue(writeOp.getAddress());
1067  llvm::Type *ty = moduleTranslation.convertType(writeOp.getValue().getType());
1068  llvm::OpenMPIRBuilder::AtomicOpValue x = {dest, ty, /*isSigned=*/false,
1069  /*isVolatile=*/false};
1070  builder.restoreIP(ompBuilder->createAtomicWrite(ompLoc, x, expr, ao));
1071  return success();
1072 }
1073 
1074 /// Converts an LLVM dialect binary operation to the corresponding enum value
1075 /// for `atomicrmw` supported binary operation.
1076 llvm::AtomicRMWInst::BinOp convertBinOpToAtomic(Operation &op) {
1078  .Case([&](LLVM::AddOp) { return llvm::AtomicRMWInst::BinOp::Add; })
1079  .Case([&](LLVM::SubOp) { return llvm::AtomicRMWInst::BinOp::Sub; })
1080  .Case([&](LLVM::AndOp) { return llvm::AtomicRMWInst::BinOp::And; })
1081  .Case([&](LLVM::OrOp) { return llvm::AtomicRMWInst::BinOp::Or; })
1082  .Case([&](LLVM::XOrOp) { return llvm::AtomicRMWInst::BinOp::Xor; })
1083  .Case([&](LLVM::UMaxOp) { return llvm::AtomicRMWInst::BinOp::UMax; })
1084  .Case([&](LLVM::UMinOp) { return llvm::AtomicRMWInst::BinOp::UMin; })
1085  .Case([&](LLVM::FAddOp) { return llvm::AtomicRMWInst::BinOp::FAdd; })
1086  .Case([&](LLVM::FSubOp) { return llvm::AtomicRMWInst::BinOp::FSub; })
1087  .Default(llvm::AtomicRMWInst::BinOp::BAD_BINOP);
1088 }
1089 
1090 /// Converts an OpenMP atomic update operation using OpenMPIRBuilder.
1091 static LogicalResult
1092 convertOmpAtomicUpdate(omp::AtomicUpdateOp &opInst,
1093  llvm::IRBuilderBase &builder,
1094  LLVM::ModuleTranslation &moduleTranslation) {
1095  llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
1096 
1097  // Convert values and types.
1098  auto &innerOpList = opInst.getRegion().front().getOperations();
1099  if (innerOpList.size() != 2)
1100  return opInst.emitError("exactly two operations are allowed inside an "
1101  "atomic update region while lowering to LLVM IR");
1102 
1103  Operation &innerUpdateOp = innerOpList.front();
1104 
1105  if (innerUpdateOp.getNumOperands() != 2 ||
1106  !llvm::is_contained(innerUpdateOp.getOperands(),
1107  opInst.getRegion().getArgument(0)))
1108  return opInst.emitError(
1109  "the update operation inside the region must be a binary operation and "
1110  "that update operation must have the region argument as an operand");
1111 
1112  llvm::AtomicRMWInst::BinOp binop = convertBinOpToAtomic(innerUpdateOp);
1113 
1114  bool isXBinopExpr =
1115  innerUpdateOp.getNumOperands() > 0 &&
1116  innerUpdateOp.getOperand(0) == opInst.getRegion().getArgument(0);
1117 
1118  mlir::Value mlirExpr = (isXBinopExpr ? innerUpdateOp.getOperand(1)
1119  : innerUpdateOp.getOperand(0));
1120  llvm::Value *llvmExpr = moduleTranslation.lookupValue(mlirExpr);
1121  llvm::Value *llvmX = moduleTranslation.lookupValue(opInst.getX());
1122  LLVM::LLVMPointerType mlirXType =
1123  opInst.getX().getType().cast<LLVM::LLVMPointerType>();
1124  llvm::Type *llvmXElementType =
1125  moduleTranslation.convertType(mlirXType.getElementType());
1126  llvm::OpenMPIRBuilder::AtomicOpValue llvmAtomicX = {llvmX, llvmXElementType,
1127  /*isSigned=*/false,
1128  /*isVolatile=*/false};
1129 
1130  llvm::AtomicOrdering atomicOrdering =
1131  convertAtomicOrdering(opInst.getMemoryOrderVal());
1132 
1133  // Generate update code.
1134  LogicalResult updateGenStatus = success();
1135  auto updateFn = [&opInst, &moduleTranslation, &updateGenStatus](
1136  llvm::Value *atomicx,
1137  llvm::IRBuilder<> &builder) -> llvm::Value * {
1138  Block &bb = *opInst.getRegion().begin();
1139  moduleTranslation.mapValue(*opInst.getRegion().args_begin(), atomicx);
1140  moduleTranslation.mapBlock(&bb, builder.GetInsertBlock());
1141  if (failed(moduleTranslation.convertBlock(bb, true, builder))) {
1142  updateGenStatus = (opInst.emitError()
1143  << "unable to convert update operation to llvm IR");
1144  return nullptr;
1145  }
1146  omp::YieldOp yieldop = dyn_cast<omp::YieldOp>(bb.getTerminator());
1147  assert(yieldop && yieldop.getResults().size() == 1 &&
1148  "terminator must be omp.yield op and it must have exactly one "
1149  "argument");
1150  return moduleTranslation.lookupValue(yieldop.getResults()[0]);
1151  };
1152 
1153  // Handle ambiguous alloca, if any.
1154  auto allocaIP = findAllocaInsertPoint(builder, moduleTranslation);
1155  llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
1156  builder.restoreIP(ompBuilder->createAtomicUpdate(
1157  ompLoc, allocaIP, llvmAtomicX, llvmExpr, atomicOrdering, binop, updateFn,
1158  isXBinopExpr));
1159  return updateGenStatus;
1160 }
1161 
1162 static LogicalResult
1163 convertOmpAtomicCapture(omp::AtomicCaptureOp atomicCaptureOp,
1164  llvm::IRBuilderBase &builder,
1165  LLVM::ModuleTranslation &moduleTranslation) {
1166  llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
1167  mlir::Value mlirExpr;
1168  bool isXBinopExpr = false, isPostfixUpdate = false;
1169  llvm::AtomicRMWInst::BinOp binop = llvm::AtomicRMWInst::BinOp::BAD_BINOP;
1170 
1171  omp::AtomicUpdateOp atomicUpdateOp = atomicCaptureOp.getAtomicUpdateOp();
1172  omp::AtomicWriteOp atomicWriteOp = atomicCaptureOp.getAtomicWriteOp();
1173 
1174  assert((atomicUpdateOp || atomicWriteOp) &&
1175  "internal op must be an atomic.update or atomic.write op");
1176 
1177  if (atomicWriteOp) {
1178  isPostfixUpdate = true;
1179  mlirExpr = atomicWriteOp.getValue();
1180  } else {
1181  isPostfixUpdate = atomicCaptureOp.getSecondOp() ==
1182  atomicCaptureOp.getAtomicUpdateOp().getOperation();
1183  auto &innerOpList = atomicUpdateOp.getRegion().front().getOperations();
1184  if (innerOpList.size() != 2)
1185  return atomicUpdateOp.emitError(
1186  "exactly two operations are allowed inside an "
1187  "atomic update region while lowering to LLVM IR");
1188  Operation *innerUpdateOp = atomicUpdateOp.getFirstOp();
1189  if (innerUpdateOp->getNumOperands() != 2 ||
1190  !llvm::is_contained(innerUpdateOp->getOperands(),
1191  atomicUpdateOp.getRegion().getArgument(0)))
1192  return atomicUpdateOp.emitError(
1193  "the update operation inside the region must be a binary operation "
1194  "and that update operation must have the region argument as an "
1195  "operand");
1196  binop = convertBinOpToAtomic(*innerUpdateOp);
1197 
1198  isXBinopExpr = innerUpdateOp->getOperand(0) ==
1199  atomicUpdateOp.getRegion().getArgument(0);
1200 
1201  mlirExpr = (isXBinopExpr ? innerUpdateOp->getOperand(1)
1202  : innerUpdateOp->getOperand(0));
1203  }
1204 
1205  llvm::Value *llvmExpr = moduleTranslation.lookupValue(mlirExpr);
1206  llvm::Value *llvmX =
1207  moduleTranslation.lookupValue(atomicCaptureOp.getAtomicReadOp().getX());
1208  llvm::Value *llvmV =
1209  moduleTranslation.lookupValue(atomicCaptureOp.getAtomicReadOp().getV());
1210  auto mlirXType = atomicCaptureOp.getAtomicReadOp()
1211  .getX()
1212  .getType()
1213  .cast<LLVM::LLVMPointerType>();
1214  llvm::Type *llvmXElementType =
1215  moduleTranslation.convertType(mlirXType.getElementType());
1216  llvm::OpenMPIRBuilder::AtomicOpValue llvmAtomicX = {llvmX, llvmXElementType,
1217  /*isSigned=*/false,
1218  /*isVolatile=*/false};
1219  llvm::OpenMPIRBuilder::AtomicOpValue llvmAtomicV = {llvmV, llvmXElementType,
1220  /*isSigned=*/false,
1221  /*isVolatile=*/false};
1222 
1223  llvm::AtomicOrdering atomicOrdering =
1224  convertAtomicOrdering(atomicCaptureOp.getMemoryOrderVal());
1225 
1226  LogicalResult updateGenStatus = success();
1227  auto updateFn = [&](llvm::Value *atomicx,
1228  llvm::IRBuilder<> &builder) -> llvm::Value * {
1229  if (atomicWriteOp)
1230  return moduleTranslation.lookupValue(atomicWriteOp.getValue());
1231  Block &bb = *atomicUpdateOp.getRegion().begin();
1232  moduleTranslation.mapValue(*atomicUpdateOp.getRegion().args_begin(),
1233  atomicx);
1234  moduleTranslation.mapBlock(&bb, builder.GetInsertBlock());
1235  if (failed(moduleTranslation.convertBlock(bb, true, builder))) {
1236  updateGenStatus = (atomicUpdateOp.emitError()
1237  << "unable to convert update operation to llvm IR");
1238  return nullptr;
1239  }
1240  omp::YieldOp yieldop = dyn_cast<omp::YieldOp>(bb.getTerminator());
1241  assert(yieldop && yieldop.getResults().size() == 1 &&
1242  "terminator must be omp.yield op and it must have exactly one "
1243  "argument");
1244  return moduleTranslation.lookupValue(yieldop.getResults()[0]);
1245  };
1246 
1247  // Handle ambiguous alloca, if any.
1248  auto allocaIP = findAllocaInsertPoint(builder, moduleTranslation);
1249  llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
1250  builder.restoreIP(ompBuilder->createAtomicCapture(
1251  ompLoc, allocaIP, llvmAtomicX, llvmAtomicV, llvmExpr, atomicOrdering,
1252  binop, updateFn, atomicUpdateOp, isPostfixUpdate, isXBinopExpr));
1253  return updateGenStatus;
1254 }
1255 
1256 /// Converts an OpenMP reduction operation using OpenMPIRBuilder. Expects the
1257 /// mapping between reduction variables and their private equivalents to have
1258 /// been stored on the ModuleTranslation stack. Currently only supports
1259 /// reduction within WsLoopOp, but can be easily extended.
1260 static LogicalResult
1261 convertOmpReductionOp(omp::ReductionOp reductionOp,
1262  llvm::IRBuilderBase &builder,
1263  LLVM::ModuleTranslation &moduleTranslation) {
1264  // Find the declaration that corresponds to the reduction op.
1265  auto reductionContainer = reductionOp->getParentOfType<omp::WsLoopOp>();
1266  omp::ReductionDeclareOp declaration =
1267  findReductionDecl(reductionContainer, reductionOp);
1268  assert(declaration && "could not find reduction declaration");
1269 
1270  // Retrieve the mapping between reduction variables and their private
1271  // equivalents.
1272  const DenseMap<Value, llvm::Value *> *reductionVariableMap = nullptr;
1273  moduleTranslation.stackWalk<OpenMPVarMappingStackFrame>(
1274  [&](const OpenMPVarMappingStackFrame &frame) {
1275  reductionVariableMap = &frame.mapping;
1276  return WalkResult::interrupt();
1277  });
1278  assert(reductionVariableMap && "couldn't find private reduction variables");
1279 
1280  // Translate the reduction operation by emitting the body of the corresponding
1281  // reduction declaration.
1282  Region &reductionRegion = declaration.getReductionRegion();
1283  llvm::Value *privateReductionVar =
1284  reductionVariableMap->lookup(reductionOp.getAccumulator());
1285  llvm::Value *reductionVal = builder.CreateLoad(
1286  moduleTranslation.convertType(reductionOp.getOperand().getType()),
1287  privateReductionVar);
1288 
1289  moduleTranslation.mapValue(reductionRegion.front().getArgument(0),
1290  reductionVal);
1291  moduleTranslation.mapValue(
1292  reductionRegion.front().getArgument(1),
1293  moduleTranslation.lookupValue(reductionOp.getOperand()));
1294 
1296  if (failed(inlineConvertOmpRegions(reductionRegion, "omp.reduction.body",
1297  builder, moduleTranslation, &phis)))
1298  return failure();
1299  assert(phis.size() == 1 && "expected one value to be yielded from "
1300  "the reduction body declaration region");
1301  builder.CreateStore(phis[0], privateReductionVar);
1302  return success();
1303 }
1304 
1305 /// Converts an OpenMP Threadprivate operation into LLVM IR using
1306 /// OpenMPIRBuilder.
1307 static LogicalResult
1308 convertOmpThreadprivate(Operation &opInst, llvm::IRBuilderBase &builder,
1309  LLVM::ModuleTranslation &moduleTranslation) {
1310  llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
1311  auto threadprivateOp = cast<omp::ThreadprivateOp>(opInst);
1312 
1313  Value symAddr = threadprivateOp.getSymAddr();
1314  auto *symOp = symAddr.getDefiningOp();
1315  if (!isa<LLVM::AddressOfOp>(symOp))
1316  return opInst.emitError("Addressing symbol not found");
1317  LLVM::AddressOfOp addressOfOp = dyn_cast<LLVM::AddressOfOp>(symOp);
1318 
1319  LLVM::GlobalOp global =
1320  addressOfOp.getGlobal(moduleTranslation.symbolTable());
1321  llvm::GlobalValue *globalValue = moduleTranslation.lookupGlobal(global);
1322  llvm::Value *data =
1323  builder.CreateBitCast(globalValue, builder.getInt8PtrTy());
1324  llvm::Type *type = globalValue->getValueType();
1325  llvm::TypeSize typeSize =
1326  builder.GetInsertBlock()->getModule()->getDataLayout().getTypeStoreSize(
1327  type);
1328  llvm::ConstantInt *size = builder.getInt64(typeSize.getFixedSize());
1329  llvm::StringRef suffix = llvm::StringRef(".cache", 6);
1330  std::string cacheName = (Twine(global.getSymName()).concat(suffix)).str();
1331  // Emit runtime function and bitcast its type (i8*) to real data type.
1332  llvm::Value *callInst =
1333  moduleTranslation.getOpenMPBuilder()->createCachedThreadPrivate(
1334  ompLoc, data, size, cacheName);
1335  llvm::Value *result = builder.CreateBitCast(callInst, globalValue->getType());
1336  moduleTranslation.mapValue(opInst.getResult(0), result);
1337  return success();
1338 }
1339 
1340 namespace {
1341 
1342 /// Implementation of the dialect interface that converts operations belonging
1343 /// to the OpenMP dialect to LLVM IR.
1344 class OpenMPDialectLLVMIRTranslationInterface
1346 public:
1348 
1349  /// Translates the given operation to LLVM IR using the provided IR builder
1350  /// and saving the state in `moduleTranslation`.
1352  convertOperation(Operation *op, llvm::IRBuilderBase &builder,
1353  LLVM::ModuleTranslation &moduleTranslation) const final;
1354 };
1355 
1356 } // namespace
1357 
1358 /// Given an OpenMP MLIR operation, create the corresponding LLVM IR
1359 /// (including OpenMP runtime calls).
1360 LogicalResult OpenMPDialectLLVMIRTranslationInterface::convertOperation(
1361  Operation *op, llvm::IRBuilderBase &builder,
1362  LLVM::ModuleTranslation &moduleTranslation) const {
1363 
1364  llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
1365 
1367  .Case([&](omp::BarrierOp) {
1368  ompBuilder->createBarrier(builder.saveIP(), llvm::omp::OMPD_barrier);
1369  return success();
1370  })
1371  .Case([&](omp::TaskwaitOp) {
1372  ompBuilder->createTaskwait(builder.saveIP());
1373  return success();
1374  })
1375  .Case([&](omp::TaskyieldOp) {
1376  ompBuilder->createTaskyield(builder.saveIP());
1377  return success();
1378  })
1379  .Case([&](omp::FlushOp) {
1380  // No support in Openmp runtime function (__kmpc_flush) to accept
1381  // the argument list.
1382  // OpenMP standard states the following:
1383  // "An implementation may implement a flush with a list by ignoring
1384  // the list, and treating it the same as a flush without a list."
1385  //
1386  // The argument list is discarded so that, flush with a list is treated
1387  // same as a flush without a list.
1388  ompBuilder->createFlush(builder.saveIP());
1389  return success();
1390  })
1391  .Case([&](omp::ParallelOp op) {
1392  return convertOmpParallel(op, builder, moduleTranslation);
1393  })
1394  .Case([&](omp::ReductionOp reductionOp) {
1395  return convertOmpReductionOp(reductionOp, builder, moduleTranslation);
1396  })
1397  .Case([&](omp::MasterOp) {
1398  return convertOmpMaster(*op, builder, moduleTranslation);
1399  })
1400  .Case([&](omp::CriticalOp) {
1401  return convertOmpCritical(*op, builder, moduleTranslation);
1402  })
1403  .Case([&](omp::OrderedRegionOp) {
1404  return convertOmpOrderedRegion(*op, builder, moduleTranslation);
1405  })
1406  .Case([&](omp::OrderedOp) {
1407  return convertOmpOrdered(*op, builder, moduleTranslation);
1408  })
1409  .Case([&](omp::WsLoopOp) {
1410  return convertOmpWsLoop(*op, builder, moduleTranslation);
1411  })
1412  .Case([&](omp::SimdLoopOp) {
1413  return convertOmpSimdLoop(*op, builder, moduleTranslation);
1414  })
1415  .Case([&](omp::AtomicReadOp) {
1416  return convertOmpAtomicRead(*op, builder, moduleTranslation);
1417  })
1418  .Case([&](omp::AtomicWriteOp) {
1419  return convertOmpAtomicWrite(*op, builder, moduleTranslation);
1420  })
1421  .Case([&](omp::AtomicUpdateOp op) {
1422  return convertOmpAtomicUpdate(op, builder, moduleTranslation);
1423  })
1424  .Case([&](omp::AtomicCaptureOp op) {
1425  return convertOmpAtomicCapture(op, builder, moduleTranslation);
1426  })
1427  .Case([&](omp::SectionsOp) {
1428  return convertOmpSections(*op, builder, moduleTranslation);
1429  })
1430  .Case([&](omp::SingleOp op) {
1431  return convertOmpSingle(op, builder, moduleTranslation);
1432  })
1433  .Case([&](omp::TaskOp op) {
1434  return convertOmpTaskOp(op, builder, moduleTranslation);
1435  })
1436  .Case([&](omp::TaskGroupOp op) {
1437  return convertOmpTaskgroupOp(op, builder, moduleTranslation);
1438  })
1439  .Case<omp::YieldOp, omp::TerminatorOp, omp::ReductionDeclareOp,
1440  omp::CriticalDeclareOp>([](auto op) {
1441  // `yield` and `terminator` can be just omitted. The block structure
1442  // was created in the region that handles their parent operation.
1443  // `reduction.declare` will be used by reductions and is not
1444  // converted directly, skip it.
1445  // `critical.declare` is only used to declare names of critical
1446  // sections which will be used by `critical` ops and hence can be
1447  // ignored for lowering. The OpenMP IRBuilder will create unique
1448  // name for critical section names.
1449  return success();
1450  })
1451  .Case([&](omp::ThreadprivateOp) {
1452  return convertOmpThreadprivate(*op, builder, moduleTranslation);
1453  })
1454  .Default([&](Operation *inst) {
1455  return inst->emitError("unsupported OpenMP operation: ")
1456  << inst->getName();
1457  });
1458 }
1459 
1461  registry.insert<omp::OpenMPDialect>();
1462  registry.addExtension(+[](MLIRContext *ctx, omp::OpenMPDialect *dialect) {
1463  dialect->addInterfaces<OpenMPDialectLLVMIRTranslationInterface>();
1464  });
1465 }
1466 
1468  DialectRegistry registry;
1470  context.appendDialectRegistry(registry);
1471 }
static LogicalResult convertOmpSimdLoop(Operation &opInst, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Converts an OpenMP simd loop into LLVM IR using OpenMPIRBuilder.
static LogicalResult convertOmpAtomicUpdate(omp::AtomicUpdateOp &opInst, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Converts an OpenMP atomic update operation using OpenMPIRBuilder.
static LogicalResult convertOmpAtomicCapture(omp::AtomicCaptureOp atomicCaptureOp, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
static LogicalResult convertOmpOrderedRegion(Operation &opInst, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Converts an OpenMP 'ordered_region' operation into LLVM IR using OpenMPIRBuilder.
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 convertOmpAtomicWrite(Operation &opInst, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Converts an omp.atomic.write operation to LLVM IR.
static LogicalResult convertOmpMaster(Operation &opInst, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Converts an OpenMP 'master' operation into LLVM IR using OpenMPIRBuilder.
static LogicalResult convertOmpTaskgroupOp(omp::TaskGroupOp tgOp, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Converts an OpenMP taskgroup construct into LLVM IR using OpenMPIRBuilder.
static OwningReductionGen makeReductionGen(omp::ReductionDeclareOp decl, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Create an OpenMPIRBuilder-compatible reduction generator for the given reduction declaration.
static LogicalResult convertOmpReductionOp(omp::ReductionOp reductionOp, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Converts an OpenMP reduction operation using OpenMPIRBuilder.
static void collectReductionDecls(omp::WsLoopOp loop, SmallVectorImpl< omp::ReductionDeclareOp > &reductions)
Populates reductions with reduction declarations used in the given loop.
static LogicalResult convertOmpTaskOp(omp::TaskOp taskOp, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Converts an OpenMP task construct into LLVM IR using OpenMPIRBuilder.
llvm::AtomicRMWInst::BinOp convertBinOpToAtomic(Operation &op)
Converts an LLVM dialect binary operation to the corresponding enum value for atomicrmw supported bin...
llvm::AtomicOrdering convertAtomicOrdering(Optional< omp::ClauseMemoryOrderKind > ao)
Convert an Atomic Ordering attribute to llvm::AtomicOrdering.
static LogicalResult convertOmpSections(Operation &opInst, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
static LogicalResult convertOmpCritical(Operation &opInst, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Converts an OpenMP 'critical' operation into LLVM IR using OpenMPIRBuilder.
static LogicalResult convertOmpOrdered(Operation &opInst, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Converts an OpenMP 'ordered' operation into LLVM IR using OpenMPIRBuilder.
static LogicalResult convertOmpParallel(omp::ParallelOp opInst, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Converts the OpenMP parallel operation to LLVM IR.
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...
static LogicalResult convertOmpThreadprivate(Operation &opInst, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Converts an OpenMP Threadprivate operation into LLVM IR using OpenMPIRBuilder.
static OwningAtomicReductionGen makeAtomicReductionGen(omp::ReductionDeclareOp decl, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Create an OpenMPIRBuilder-compatible atomic reduction generator for the given reduction declaration.
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...
static llvm::omp::ProcBindKind getProcBindKind(omp::ClauseProcBindKind kind)
Convert ProcBindKind from MLIR-generated enum to LLVM enum.
static LogicalResult convertOmpSingle(omp::SingleOp &singleOp, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Converts an OpenMP single construct into LLVM IR using OpenMPIRBuilder.
static LogicalResult convertOmpWsLoop(Operation &opInst, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Converts an OpenMP workshare loop into LLVM IR using OpenMPIRBuilder.
static LogicalResult convertOmpAtomicRead(Operation &opInst, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Convert omp.atomic.read operation to LLVM IR.
static llvm::BasicBlock * convertOmpOpRegions(Region &region, StringRef blockName, 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,...
static Type getElementType(Type type, ArrayRef< int32_t > indices, function_ref< InFlightDiagnostic(StringRef)> emitErrorFn)
Walks the given type hierarchy with the given indices, potentially down to component granularity,...
Definition: SPIRVOps.cpp:696
#define MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(CLASS_NAME)
Definition: TypeID.h:274
Block represents an ordered list of Operations.
Definition: Block.h:30
BlockArgument getArgument(unsigned i)
Definition: Block.h:118
Operation & back()
Definition: Block.h:141
Operation * getTerminator()
Get the terminator operation of this block.
Definition: Block.cpp:232
iterator begin()
Definition: Block.h:132
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
void addExtension(std::unique_ptr< DialectExtensionBase > extension)
Add the given extension to the registry.
Base class for dialect interfaces providing translation to LLVM IR.
Concrete CRTP base class for ModuleTranslation stack frames.
Implementation class for module translation.
LogicalResult convertBlock(Block &bb, bool ignoreArguments, llvm::IRBuilderBase &builder)
Translates the contents of the given block to LLVM IR using this translator.
llvm::Value * lookupValue(Value value) const
Finds an LLVM IR value corresponding to the given MLIR value.
SmallVector< llvm::Value * > lookupValues(ValueRange values)
Looks up remapped a list of remapped values.
llvm::BasicBlock * lookupBlock(Block *block) const
Finds an LLVM IR basic block that corresponds to the given MLIR block.
SymbolTableCollection & symbolTable()
llvm::Type * convertType(Type type)
Converts the type from MLIR LLVM dialect to LLVM.
llvm::OpenMPIRBuilder * getOpenMPBuilder()
Returns the OpenMP IR builder associated with the LLVM IR module being constructed.
llvm::LLVMContext & getLLVMContext() const
Returns the LLVM context in which the IR is being constructed.
llvm::GlobalValue * lookupGlobal(Operation *op)
Finds an LLVM IR global value that corresponds to the given MLIR operation defining a global value.
void mapBlock(Block *mlir, llvm::BasicBlock *llvm)
Stores the mapping between an MLIR block and LLVM IR basic block.
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 forgetMapping(Region &region)
Removes the mapping for blocks contained in the region and values defined in these blocks.
void mapValue(Value mlir, llvm::Value *llvm)
Stores the mapping between an MLIR value and its LLVM IR counterpart.
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:56
void appendDialectRegistry(const DialectRegistry &registry)
Append the contents of the given dialect registry to the registry associated with this context.
Operation is a basic unit of execution within MLIR.
Definition: Operation.h:31
Value getOperand(unsigned idx)
Definition: Operation.h:267
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Definition: Operation.h:324
unsigned getNumOperands()
Definition: Operation.h:263
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
Definition: Operation.cpp:225
Region & getRegion(unsigned index)
Returns the region held by this operation at position 'index'.
Definition: Operation.h:486
OperationName getName()
The name of an operation is the key identifier for it.
Definition: Operation.h:50
operand_range getOperands()
Returns an iterator on the underlying Value's.
Definition: Operation.h:295
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition: Region.h:26
bool empty()
Definition: Region.h:60
iterator begin()
Definition: Region.h:55
BlockListType & getBlocks()
Definition: Region.h:45
Block & front()
Definition: Region.h:65
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
U cast() const
Definition: Types.h:280
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:85
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Definition: Value.cpp:20
A utility result that is used to signal how to proceed with an ongoing walk:
Definition: Visitors.h:34
bool wasInterrupted() const
Returns true if the walk was interrupted.
Definition: Visitors.h:55
static WalkResult interrupt()
Definition: Visitors.h:50
void connectPHINodes(Region &region, const ModuleTranslation &state)
For all blocks in the region that were converted to LLVM IR using the given ModuleTranslation,...
SetVector< Block * > getTopologicallySortedBlocks(Region &region)
Get a topologically sorted list of blocks of the given region.
Runtime
Potential runtimes for AMD GPU kernels.
Definition: Runtimes.h:15
Include the generated interface declarations.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
void registerOpenMPDialectTranslation(DialectRegistry &registry)
Register the OpenMP dialect and the translation from it to the LLVM IR in the given registry;.
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
Definition: LogicalResult.h:72
RAII object calling stackPush/stackPop on construction/destruction.
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26