MLIR  20.0.0git
OpenMPDialect.cpp
Go to the documentation of this file.
1 //===- OpenMPDialect.cpp - MLIR Dialect for OpenMP implementation ---------===//
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 the OpenMP dialect and its operations.
10 //
11 //===----------------------------------------------------------------------===//
12 
17 #include "mlir/IR/Attributes.h"
23 
24 #include "llvm/ADT/ArrayRef.h"
25 #include "llvm/ADT/BitVector.h"
26 #include "llvm/ADT/STLExtras.h"
27 #include "llvm/ADT/STLForwardCompat.h"
28 #include "llvm/ADT/SmallString.h"
29 #include "llvm/ADT/StringExtras.h"
30 #include "llvm/ADT/StringRef.h"
31 #include "llvm/ADT/TypeSwitch.h"
32 #include "llvm/Frontend/OpenMP/OMPConstants.h"
33 #include <cstddef>
34 #include <iterator>
35 #include <optional>
36 #include <variant>
37 
38 #include "mlir/Dialect/OpenMP/OpenMPOpsDialect.cpp.inc"
39 #include "mlir/Dialect/OpenMP/OpenMPOpsEnums.cpp.inc"
40 #include "mlir/Dialect/OpenMP/OpenMPOpsInterfaces.cpp.inc"
41 #include "mlir/Dialect/OpenMP/OpenMPTypeInterfaces.cpp.inc"
42 
43 using namespace mlir;
44 using namespace mlir::omp;
45 
46 static ArrayAttr makeArrayAttr(MLIRContext *context,
48  return attrs.empty() ? nullptr : ArrayAttr::get(context, attrs);
49 }
50 
51 static DenseBoolArrayAttr
53  return boolArray.empty() ? nullptr : DenseBoolArrayAttr::get(ctx, boolArray);
54 }
55 
56 namespace {
57 struct MemRefPointerLikeModel
58  : public PointerLikeType::ExternalModel<MemRefPointerLikeModel,
59  MemRefType> {
60  Type getElementType(Type pointer) const {
61  return llvm::cast<MemRefType>(pointer).getElementType();
62  }
63 };
64 
65 struct LLVMPointerPointerLikeModel
66  : public PointerLikeType::ExternalModel<LLVMPointerPointerLikeModel,
67  LLVM::LLVMPointerType> {
68  Type getElementType(Type pointer) const { return Type(); }
69 };
70 } // namespace
71 
72 void OpenMPDialect::initialize() {
73  addOperations<
74 #define GET_OP_LIST
75 #include "mlir/Dialect/OpenMP/OpenMPOps.cpp.inc"
76  >();
77  addAttributes<
78 #define GET_ATTRDEF_LIST
79 #include "mlir/Dialect/OpenMP/OpenMPOpsAttributes.cpp.inc"
80  >();
81  addTypes<
82 #define GET_TYPEDEF_LIST
83 #include "mlir/Dialect/OpenMP/OpenMPOpsTypes.cpp.inc"
84  >();
85 
86  MemRefType::attachInterface<MemRefPointerLikeModel>(*getContext());
87  LLVM::LLVMPointerType::attachInterface<LLVMPointerPointerLikeModel>(
88  *getContext());
89 
90  // Attach default offload module interface to module op to access
91  // offload functionality through
92  mlir::ModuleOp::attachInterface<mlir::omp::OffloadModuleDefaultModel>(
93  *getContext());
94 
95  // Attach default declare target interfaces to operations which can be marked
96  // as declare target (Global Operations and Functions/Subroutines in dialects
97  // that Fortran (or other languages that lower to MLIR) translates too
98  mlir::LLVM::GlobalOp::attachInterface<
100  *getContext());
101  mlir::LLVM::LLVMFuncOp::attachInterface<
103  *getContext());
104  mlir::func::FuncOp::attachInterface<
106 }
107 
108 //===----------------------------------------------------------------------===//
109 // Parser and printer for Allocate Clause
110 //===----------------------------------------------------------------------===//
111 
112 /// Parse an allocate clause with allocators and a list of operands with types.
113 ///
114 /// allocate-operand-list :: = allocate-operand |
115 /// allocator-operand `,` allocate-operand-list
116 /// allocate-operand :: = ssa-id-and-type -> ssa-id-and-type
117 /// ssa-id-and-type ::= ssa-id `:` type
118 static ParseResult parseAllocateAndAllocator(
119  OpAsmParser &parser,
121  SmallVectorImpl<Type> &typesAllocate,
123  SmallVectorImpl<Type> &typesAllocator) {
124 
125  return parser.parseCommaSeparatedList([&]() {
127  Type type;
128  if (parser.parseOperand(operand) || parser.parseColonType(type))
129  return failure();
130  operandsAllocator.push_back(operand);
131  typesAllocator.push_back(type);
132  if (parser.parseArrow())
133  return failure();
134  if (parser.parseOperand(operand) || parser.parseColonType(type))
135  return failure();
136 
137  operandsAllocate.push_back(operand);
138  typesAllocate.push_back(type);
139  return success();
140  });
141 }
142 
143 /// Print allocate clause
145  OperandRange varsAllocate,
146  TypeRange typesAllocate,
147  OperandRange varsAllocator,
148  TypeRange typesAllocator) {
149  for (unsigned i = 0; i < varsAllocate.size(); ++i) {
150  std::string separator = i == varsAllocate.size() - 1 ? "" : ", ";
151  p << varsAllocator[i] << " : " << typesAllocator[i] << " -> ";
152  p << varsAllocate[i] << " : " << typesAllocate[i] << separator;
153  }
154 }
155 
156 //===----------------------------------------------------------------------===//
157 // Parser and printer for a clause attribute (StringEnumAttr)
158 //===----------------------------------------------------------------------===//
159 
160 template <typename ClauseAttr>
161 static ParseResult parseClauseAttr(AsmParser &parser, ClauseAttr &attr) {
162  using ClauseT = decltype(std::declval<ClauseAttr>().getValue());
163  StringRef enumStr;
164  SMLoc loc = parser.getCurrentLocation();
165  if (parser.parseKeyword(&enumStr))
166  return failure();
167  if (std::optional<ClauseT> enumValue = symbolizeEnum<ClauseT>(enumStr)) {
168  attr = ClauseAttr::get(parser.getContext(), *enumValue);
169  return success();
170  }
171  return parser.emitError(loc, "invalid clause value: '") << enumStr << "'";
172 }
173 
174 template <typename ClauseAttr>
175 void printClauseAttr(OpAsmPrinter &p, Operation *op, ClauseAttr attr) {
176  p << stringifyEnum(attr.getValue());
177 }
178 
179 //===----------------------------------------------------------------------===//
180 // Parser and printer for Linear Clause
181 //===----------------------------------------------------------------------===//
182 
183 /// linear ::= `linear` `(` linear-list `)`
184 /// linear-list := linear-val | linear-val linear-list
185 /// linear-val := ssa-id-and-type `=` ssa-id-and-type
186 static ParseResult
189  SmallVectorImpl<Type> &types,
191  return parser.parseCommaSeparatedList([&]() {
193  Type type;
195  if (parser.parseOperand(var) || parser.parseEqual() ||
196  parser.parseOperand(stepVar) || parser.parseColonType(type))
197  return failure();
198 
199  vars.push_back(var);
200  types.push_back(type);
201  stepVars.push_back(stepVar);
202  return success();
203  });
204 }
205 
206 /// Print Linear Clause
208  ValueRange linearVars, TypeRange linearVarTypes,
209  ValueRange linearStepVars) {
210  size_t linearVarsSize = linearVars.size();
211  for (unsigned i = 0; i < linearVarsSize; ++i) {
212  std::string separator = i == linearVarsSize - 1 ? "" : ", ";
213  p << linearVars[i];
214  if (linearStepVars.size() > i)
215  p << " = " << linearStepVars[i];
216  p << " : " << linearVars[i].getType() << separator;
217  }
218 }
219 
220 //===----------------------------------------------------------------------===//
221 // Verifier for Nontemporal Clause
222 //===----------------------------------------------------------------------===//
223 
224 static LogicalResult
225 verifyNontemporalClause(Operation *op, OperandRange nontemporalVariables) {
226 
227  // Check if each var is unique - OpenMP 5.0 -> 2.9.3.1 section
228  DenseSet<Value> nontemporalItems;
229  for (const auto &it : nontemporalVariables)
230  if (!nontemporalItems.insert(it).second)
231  return op->emitOpError() << "nontemporal variable used more than once";
232 
233  return success();
234 }
235 
236 //===----------------------------------------------------------------------===//
237 // Parser, verifier and printer for Aligned Clause
238 //===----------------------------------------------------------------------===//
239 static LogicalResult
240 verifyAlignedClause(Operation *op, std::optional<ArrayAttr> alignmentValues,
241  OperandRange alignedVariables) {
242  // Check if number of alignment values equals to number of aligned variables
243  if (!alignedVariables.empty()) {
244  if (!alignmentValues || alignmentValues->size() != alignedVariables.size())
245  return op->emitOpError()
246  << "expected as many alignment values as aligned variables";
247  } else {
248  if (alignmentValues)
249  return op->emitOpError() << "unexpected alignment values attribute";
250  return success();
251  }
252 
253  // Check if each var is aligned only once - OpenMP 4.5 -> 2.8.1 section
254  DenseSet<Value> alignedItems;
255  for (auto it : alignedVariables)
256  if (!alignedItems.insert(it).second)
257  return op->emitOpError() << "aligned variable used more than once";
258 
259  if (!alignmentValues)
260  return success();
261 
262  // Check if all alignment values are positive - OpenMP 4.5 -> 2.8.1 section
263  for (unsigned i = 0; i < (*alignmentValues).size(); ++i) {
264  if (auto intAttr = llvm::dyn_cast<IntegerAttr>((*alignmentValues)[i])) {
265  if (intAttr.getValue().sle(0))
266  return op->emitOpError() << "alignment should be greater than 0";
267  } else {
268  return op->emitOpError() << "expected integer alignment";
269  }
270  }
271 
272  return success();
273 }
274 
275 /// aligned ::= `aligned` `(` aligned-list `)`
276 /// aligned-list := aligned-val | aligned-val aligned-list
277 /// aligned-val := ssa-id-and-type `->` alignment
278 static ParseResult parseAlignedClause(
279  OpAsmParser &parser,
281  SmallVectorImpl<Type> &types, ArrayAttr &alignmentValues) {
282  SmallVector<Attribute> alignmentVec;
283  if (failed(parser.parseCommaSeparatedList([&]() {
284  if (parser.parseOperand(alignedItems.emplace_back()) ||
285  parser.parseColonType(types.emplace_back()) ||
286  parser.parseArrow() ||
287  parser.parseAttribute(alignmentVec.emplace_back())) {
288  return failure();
289  }
290  return success();
291  })))
292  return failure();
293  SmallVector<Attribute> alignments(alignmentVec.begin(), alignmentVec.end());
294  alignmentValues = ArrayAttr::get(parser.getContext(), alignments);
295  return success();
296 }
297 
298 /// Print Aligned Clause
300  ValueRange alignedVars,
301  TypeRange alignedVarTypes,
302  std::optional<ArrayAttr> alignmentValues) {
303  for (unsigned i = 0; i < alignedVars.size(); ++i) {
304  if (i != 0)
305  p << ", ";
306  p << alignedVars[i] << " : " << alignedVars[i].getType();
307  p << " -> " << (*alignmentValues)[i];
308  }
309 }
310 
311 //===----------------------------------------------------------------------===//
312 // Parser, printer and verifier for Schedule Clause
313 //===----------------------------------------------------------------------===//
314 
315 static ParseResult
317  SmallVectorImpl<SmallString<12>> &modifiers) {
318  if (modifiers.size() > 2)
319  return parser.emitError(parser.getNameLoc()) << " unexpected modifier(s)";
320  for (const auto &mod : modifiers) {
321  // Translate the string. If it has no value, then it was not a valid
322  // modifier!
323  auto symbol = symbolizeScheduleModifier(mod);
324  if (!symbol)
325  return parser.emitError(parser.getNameLoc())
326  << " unknown modifier type: " << mod;
327  }
328 
329  // If we have one modifier that is "simd", then stick a "none" modiifer in
330  // index 0.
331  if (modifiers.size() == 1) {
332  if (symbolizeScheduleModifier(modifiers[0]) == ScheduleModifier::simd) {
333  modifiers.push_back(modifiers[0]);
334  modifiers[0] = stringifyScheduleModifier(ScheduleModifier::none);
335  }
336  } else if (modifiers.size() == 2) {
337  // If there are two modifier:
338  // First modifier should not be simd, second one should be simd
339  if (symbolizeScheduleModifier(modifiers[0]) == ScheduleModifier::simd ||
340  symbolizeScheduleModifier(modifiers[1]) != ScheduleModifier::simd)
341  return parser.emitError(parser.getNameLoc())
342  << " incorrect modifier order";
343  }
344  return success();
345 }
346 
347 /// schedule ::= `schedule` `(` sched-list `)`
348 /// sched-list ::= sched-val | sched-val sched-list |
349 /// sched-val `,` sched-modifier
350 /// sched-val ::= sched-with-chunk | sched-wo-chunk
351 /// sched-with-chunk ::= sched-with-chunk-types (`=` ssa-id-and-type)?
352 /// sched-with-chunk-types ::= `static` | `dynamic` | `guided`
353 /// sched-wo-chunk ::= `auto` | `runtime`
354 /// sched-modifier ::= sched-mod-val | sched-mod-val `,` sched-mod-val
355 /// sched-mod-val ::= `monotonic` | `nonmonotonic` | `simd` | `none`
356 static ParseResult parseScheduleClause(
357  OpAsmParser &parser, ClauseScheduleKindAttr &scheduleAttr,
358  ScheduleModifierAttr &scheduleModifier, UnitAttr &simdModifier,
359  std::optional<OpAsmParser::UnresolvedOperand> &chunkSize, Type &chunkType) {
360  StringRef keyword;
361  if (parser.parseKeyword(&keyword))
362  return failure();
363  std::optional<mlir::omp::ClauseScheduleKind> schedule =
364  symbolizeClauseScheduleKind(keyword);
365  if (!schedule)
366  return parser.emitError(parser.getNameLoc()) << " expected schedule kind";
367 
368  scheduleAttr = ClauseScheduleKindAttr::get(parser.getContext(), *schedule);
369  switch (*schedule) {
370  case ClauseScheduleKind::Static:
371  case ClauseScheduleKind::Dynamic:
372  case ClauseScheduleKind::Guided:
373  if (succeeded(parser.parseOptionalEqual())) {
374  chunkSize = OpAsmParser::UnresolvedOperand{};
375  if (parser.parseOperand(*chunkSize) || parser.parseColonType(chunkType))
376  return failure();
377  } else {
378  chunkSize = std::nullopt;
379  }
380  break;
381  case ClauseScheduleKind::Auto:
383  chunkSize = std::nullopt;
384  }
385 
386  // If there is a comma, we have one or more modifiers..
387  SmallVector<SmallString<12>> modifiers;
388  while (succeeded(parser.parseOptionalComma())) {
389  StringRef mod;
390  if (parser.parseKeyword(&mod))
391  return failure();
392  modifiers.push_back(mod);
393  }
394 
395  if (verifyScheduleModifiers(parser, modifiers))
396  return failure();
397 
398  if (!modifiers.empty()) {
399  SMLoc loc = parser.getCurrentLocation();
400  if (std::optional<ScheduleModifier> mod =
401  symbolizeScheduleModifier(modifiers[0])) {
402  scheduleModifier = ScheduleModifierAttr::get(parser.getContext(), *mod);
403  } else {
404  return parser.emitError(loc, "invalid schedule modifier");
405  }
406  // Only SIMD attribute is allowed here!
407  if (modifiers.size() > 1) {
408  assert(symbolizeScheduleModifier(modifiers[1]) == ScheduleModifier::simd);
409  simdModifier = UnitAttr::get(parser.getBuilder().getContext());
410  }
411  }
412 
413  return success();
414 }
415 
416 /// Print schedule clause
418  ClauseScheduleKindAttr schedAttr,
419  ScheduleModifierAttr modifier, UnitAttr simd,
420  Value scheduleChunkVar,
421  Type scheduleChunkType) {
422  p << stringifyClauseScheduleKind(schedAttr.getValue());
423  if (scheduleChunkVar)
424  p << " = " << scheduleChunkVar << " : " << scheduleChunkVar.getType();
425  if (modifier)
426  p << ", " << stringifyScheduleModifier(modifier.getValue());
427  if (simd)
428  p << ", simd";
429 }
430 
431 //===----------------------------------------------------------------------===//
432 // Parser and printer for Order Clause
433 //===----------------------------------------------------------------------===//
434 
435 // order ::= `order` `(` [order-modifier ':'] concurrent `)`
436 // order-modifier ::= reproducible | unconstrained
437 static ParseResult parseOrderClause(OpAsmParser &parser,
438  ClauseOrderKindAttr &kindAttr,
439  OrderModifierAttr &modifierAttr) {
440  StringRef enumStr;
441  SMLoc loc = parser.getCurrentLocation();
442  if (parser.parseKeyword(&enumStr))
443  return failure();
444  if (std::optional<OrderModifier> enumValue =
445  symbolizeOrderModifier(enumStr)) {
446  modifierAttr = OrderModifierAttr::get(parser.getContext(), *enumValue);
447  if (parser.parseOptionalColon())
448  return failure();
449  loc = parser.getCurrentLocation();
450  if (parser.parseKeyword(&enumStr))
451  return failure();
452  }
453  if (std::optional<ClauseOrderKind> enumValue =
454  symbolizeClauseOrderKind(enumStr)) {
455  kindAttr = ClauseOrderKindAttr::get(parser.getContext(), *enumValue);
456  return success();
457  }
458  return parser.emitError(loc, "invalid clause value: '") << enumStr << "'";
459 }
460 
462  ClauseOrderKindAttr kindAttr,
463  OrderModifierAttr modifierAttr) {
464  if (modifierAttr)
465  p << stringifyOrderModifier(modifierAttr.getValue()) << ":";
466  if (kindAttr)
467  p << stringifyClauseOrderKind(kindAttr.getValue());
468 }
469 
470 //===----------------------------------------------------------------------===//
471 // Parser, printer and verifier for ReductionVarList
472 //===----------------------------------------------------------------------===//
473 
474 static ParseResult parseClauseWithRegionArgs(
475  OpAsmParser &parser, Region &region,
477  SmallVectorImpl<Type> &types, DenseBoolArrayAttr &isByRef,
478  ArrayAttr &symbols,
479  SmallVectorImpl<OpAsmParser::Argument> &regionPrivateArgs) {
480  SmallVector<SymbolRefAttr> reductionVec;
481  SmallVector<bool> isByRefVec;
482  unsigned regionArgOffset = regionPrivateArgs.size();
483 
484  if (failed(
486  ParseResult optionalByref = parser.parseOptionalKeyword("byref");
487  if (parser.parseAttribute(reductionVec.emplace_back()) ||
488  parser.parseOperand(operands.emplace_back()) ||
489  parser.parseArrow() ||
490  parser.parseArgument(regionPrivateArgs.emplace_back()) ||
491  parser.parseColonType(types.emplace_back()))
492  return failure();
493  isByRefVec.push_back(optionalByref.succeeded());
494  return success();
495  })))
496  return failure();
497  isByRef = makeDenseBoolArrayAttr(parser.getContext(), isByRefVec);
498 
499  auto *argsBegin = regionPrivateArgs.begin();
500  MutableArrayRef argsSubrange(argsBegin + regionArgOffset,
501  argsBegin + regionArgOffset + types.size());
502  for (auto [prv, type] : llvm::zip_equal(argsSubrange, types)) {
503  prv.type = type;
504  }
505  SmallVector<Attribute> reductions(reductionVec.begin(), reductionVec.end());
506  symbols = ArrayAttr::get(parser.getContext(), reductions);
507  return success();
508 }
509 
511  ValueRange argsSubrange,
512  StringRef clauseName, ValueRange operands,
513  TypeRange types, DenseBoolArrayAttr byRef,
514  ArrayAttr symbols) {
515  if (!clauseName.empty())
516  p << clauseName << "(";
517 
518  llvm::interleaveComma(llvm::zip_equal(symbols, operands, argsSubrange, types,
519  byRef.asArrayRef()),
520  p, [&p](auto t) {
521  auto [sym, op, arg, type, isByRef] = t;
522  p << (isByRef ? "byref " : "") << sym << " " << op
523  << " -> " << arg << " : " << type;
524  });
525 
526  if (!clauseName.empty())
527  p << ") ";
528 }
529 
530 static ParseResult parseParallelRegion(
531  OpAsmParser &parser, Region &region,
533  SmallVectorImpl<Type> &reductionVarTypes,
534  DenseBoolArrayAttr &reductionByRef, ArrayAttr &reductionSymbols,
536  llvm::SmallVectorImpl<Type> &privateVarsTypes,
537  ArrayAttr &privatizerSymbols) {
539 
540  if (succeeded(parser.parseOptionalKeyword("reduction"))) {
541  if (failed(parseClauseWithRegionArgs(parser, region, reductionVarOperands,
542  reductionVarTypes, reductionByRef,
543  reductionSymbols, regionPrivateArgs)))
544  return failure();
545  }
546 
547  if (succeeded(parser.parseOptionalKeyword("private"))) {
548  auto privateByRef = DenseBoolArrayAttr::get(parser.getContext(), {});
549  if (failed(parseClauseWithRegionArgs(parser, region, privateVarOperands,
550  privateVarsTypes, privateByRef,
551  privatizerSymbols, regionPrivateArgs)))
552  return failure();
553  if (llvm::any_of(privateByRef.asArrayRef(),
554  [](bool byref) { return byref; })) {
555  parser.emitError(parser.getCurrentLocation(),
556  "private clause cannot have byref attributes");
557  return failure();
558  }
559  }
560 
561  return parser.parseRegion(region, regionPrivateArgs);
562 }
563 
564 static void printParallelRegion(OpAsmPrinter &p, Operation *op, Region &region,
565  ValueRange reductionVarOperands,
566  TypeRange reductionVarTypes,
567  DenseBoolArrayAttr reductionVarIsByRef,
568  ArrayAttr reductionSymbols,
569  ValueRange privateVarOperands,
570  TypeRange privateVarTypes,
571  ArrayAttr privatizerSymbols) {
572  if (reductionSymbols) {
573  auto *argsBegin = region.front().getArguments().begin();
574  MutableArrayRef argsSubrange(argsBegin,
575  argsBegin + reductionVarTypes.size());
576  printClauseWithRegionArgs(p, op, argsSubrange, "reduction",
577  reductionVarOperands, reductionVarTypes,
578  reductionVarIsByRef, reductionSymbols);
579  }
580 
581  if (privatizerSymbols) {
582  auto *argsBegin = region.front().getArguments().begin();
583  MutableArrayRef argsSubrange(argsBegin + reductionVarOperands.size(),
584  argsBegin + reductionVarOperands.size() +
585  privateVarTypes.size());
586  mlir::SmallVector<bool> isByRefVec;
587  isByRefVec.resize(privateVarTypes.size(), false);
588  DenseBoolArrayAttr isByRef =
589  makeDenseBoolArrayAttr(op->getContext(), isByRefVec);
590 
591  printClauseWithRegionArgs(p, op, argsSubrange, "private",
592  privateVarOperands, privateVarTypes, isByRef,
593  privatizerSymbols);
594  }
595 
596  p.printRegion(region, /*printEntryBlockArgs=*/false);
597 }
598 
599 /// reduction-entry-list ::= reduction-entry
600 /// | reduction-entry-list `,` reduction-entry
601 /// reduction-entry ::= (`byref`)? symbol-ref `->` ssa-id `:` type
602 static ParseResult
605  SmallVectorImpl<Type> &types, DenseBoolArrayAttr &isByRef,
606  ArrayAttr &reductionSymbols) {
607  SmallVector<SymbolRefAttr> reductionVec;
608  SmallVector<bool> isByRefVec;
609  if (failed(parser.parseCommaSeparatedList([&]() {
610  ParseResult optionalByref = parser.parseOptionalKeyword("byref");
611  if (parser.parseAttribute(reductionVec.emplace_back()) ||
612  parser.parseArrow() ||
613  parser.parseOperand(operands.emplace_back()) ||
614  parser.parseColonType(types.emplace_back()))
615  return failure();
616  isByRefVec.push_back(optionalByref.succeeded());
617  return success();
618  })))
619  return failure();
620  isByRef = makeDenseBoolArrayAttr(parser.getContext(), isByRefVec);
621  SmallVector<Attribute> reductions(reductionVec.begin(), reductionVec.end());
622  reductionSymbols = ArrayAttr::get(parser.getContext(), reductions);
623  return success();
624 }
625 
626 /// Print Reduction clause
628  OperandRange reductionVars,
629  TypeRange reductionTypes,
630  std::optional<DenseBoolArrayAttr> isByRef,
631  std::optional<ArrayAttr> reductions) {
632  auto getByRef = [&](unsigned i) -> const char * {
633  if (!isByRef || !*isByRef)
634  return "";
635  assert(isByRef->empty() || i < isByRef->size());
636  if (!isByRef->empty() && (*isByRef)[i])
637  return "byref ";
638  return "";
639  };
640 
641  for (unsigned i = 0, e = reductionVars.size(); i < e; ++i) {
642  if (i != 0)
643  p << ", ";
644  p << getByRef(i) << (*reductions)[i] << " -> " << reductionVars[i] << " : "
645  << reductionVars[i].getType();
646  }
647 }
648 
649 /// Verifies Reduction Clause
650 static LogicalResult
651 verifyReductionVarList(Operation *op, std::optional<ArrayAttr> reductions,
652  OperandRange reductionVars,
653  std::optional<ArrayRef<bool>> byRef) {
654  if (!reductionVars.empty()) {
655  if (!reductions || reductions->size() != reductionVars.size())
656  return op->emitOpError()
657  << "expected as many reduction symbol references "
658  "as reduction variables";
659  if (byRef && byRef->size() != reductionVars.size())
660  return op->emitError() << "expected as many reduction variable by "
661  "reference attributes as reduction variables";
662  } else {
663  if (reductions)
664  return op->emitOpError() << "unexpected reduction symbol references";
665  return success();
666  }
667 
668  // TODO: The followings should be done in
669  // SymbolUserOpInterface::verifySymbolUses.
670  DenseSet<Value> accumulators;
671  for (auto args : llvm::zip(reductionVars, *reductions)) {
672  Value accum = std::get<0>(args);
673 
674  if (!accumulators.insert(accum).second)
675  return op->emitOpError() << "accumulator variable used more than once";
676 
677  Type varType = accum.getType();
678  auto symbolRef = llvm::cast<SymbolRefAttr>(std::get<1>(args));
679  auto decl =
680  SymbolTable::lookupNearestSymbolFrom<DeclareReductionOp>(op, symbolRef);
681  if (!decl)
682  return op->emitOpError() << "expected symbol reference " << symbolRef
683  << " to point to a reduction declaration";
684 
685  if (decl.getAccumulatorType() && decl.getAccumulatorType() != varType)
686  return op->emitOpError()
687  << "expected accumulator (" << varType
688  << ") to be the same type as reduction declaration ("
689  << decl.getAccumulatorType() << ")";
690  }
691 
692  return success();
693 }
694 
695 //===----------------------------------------------------------------------===//
696 // Parser, printer and verifier for CopyPrivateVarList
697 //===----------------------------------------------------------------------===//
698 
699 /// copyprivate-entry-list ::= copyprivate-entry
700 /// | copyprivate-entry-list `,` copyprivate-entry
701 /// copyprivate-entry ::= ssa-id `->` symbol-ref `:` type
702 static ParseResult parseCopyPrivateVarList(
703  OpAsmParser &parser,
705  SmallVectorImpl<Type> &types, ArrayAttr &copyPrivateSymbols) {
706  SmallVector<SymbolRefAttr> copyPrivateFuncsVec;
707  if (failed(parser.parseCommaSeparatedList([&]() {
708  if (parser.parseOperand(operands.emplace_back()) ||
709  parser.parseArrow() ||
710  parser.parseAttribute(copyPrivateFuncsVec.emplace_back()) ||
711  parser.parseColonType(types.emplace_back()))
712  return failure();
713  return success();
714  })))
715  return failure();
716  SmallVector<Attribute> copyPrivateFuncs(copyPrivateFuncsVec.begin(),
717  copyPrivateFuncsVec.end());
718  copyPrivateSymbols = ArrayAttr::get(parser.getContext(), copyPrivateFuncs);
719  return success();
720 }
721 
722 /// Print CopyPrivate clause
724  OperandRange copyPrivateVars,
725  TypeRange copyPrivateTypes,
726  std::optional<ArrayAttr> copyPrivateFuncs) {
727  if (!copyPrivateFuncs.has_value())
728  return;
729  llvm::interleaveComma(
730  llvm::zip(copyPrivateVars, *copyPrivateFuncs, copyPrivateTypes), p,
731  [&](const auto &args) {
732  p << std::get<0>(args) << " -> " << std::get<1>(args) << " : "
733  << std::get<2>(args);
734  });
735 }
736 
737 /// Verifies CopyPrivate Clause
738 static LogicalResult
740  std::optional<ArrayAttr> copyPrivateFuncs) {
741  size_t copyPrivateFuncsSize =
742  copyPrivateFuncs.has_value() ? copyPrivateFuncs->size() : 0;
743  if (copyPrivateFuncsSize != copyPrivateVars.size())
744  return op->emitOpError() << "inconsistent number of copyPrivate vars (= "
745  << copyPrivateVars.size()
746  << ") and functions (= " << copyPrivateFuncsSize
747  << "), both must be equal";
748  if (!copyPrivateFuncs.has_value())
749  return success();
750 
751  for (auto copyPrivateVarAndFunc :
752  llvm::zip(copyPrivateVars, *copyPrivateFuncs)) {
753  auto symbolRef =
754  llvm::cast<SymbolRefAttr>(std::get<1>(copyPrivateVarAndFunc));
755  std::optional<std::variant<mlir::func::FuncOp, mlir::LLVM::LLVMFuncOp>>
756  funcOp;
757  if (mlir::func::FuncOp mlirFuncOp =
758  SymbolTable::lookupNearestSymbolFrom<mlir::func::FuncOp>(op,
759  symbolRef))
760  funcOp = mlirFuncOp;
761  else if (mlir::LLVM::LLVMFuncOp llvmFuncOp =
762  SymbolTable::lookupNearestSymbolFrom<mlir::LLVM::LLVMFuncOp>(
763  op, symbolRef))
764  funcOp = llvmFuncOp;
765 
766  auto getNumArguments = [&] {
767  return std::visit([](auto &f) { return f.getNumArguments(); }, *funcOp);
768  };
769 
770  auto getArgumentType = [&](unsigned i) {
771  return std::visit([i](auto &f) { return f.getArgumentTypes()[i]; },
772  *funcOp);
773  };
774 
775  if (!funcOp)
776  return op->emitOpError() << "expected symbol reference " << symbolRef
777  << " to point to a copy function";
778 
779  if (getNumArguments() != 2)
780  return op->emitOpError()
781  << "expected copy function " << symbolRef << " to have 2 operands";
782 
783  Type argTy = getArgumentType(0);
784  if (argTy != getArgumentType(1))
785  return op->emitOpError() << "expected copy function " << symbolRef
786  << " arguments to have the same type";
787 
788  Type varType = std::get<0>(copyPrivateVarAndFunc).getType();
789  if (argTy != varType)
790  return op->emitOpError()
791  << "expected copy function arguments' type (" << argTy
792  << ") to be the same as copyprivate variable's type (" << varType
793  << ")";
794  }
795 
796  return success();
797 }
798 
799 //===----------------------------------------------------------------------===//
800 // Parser, printer and verifier for DependVarList
801 //===----------------------------------------------------------------------===//
802 
803 /// depend-entry-list ::= depend-entry
804 /// | depend-entry-list `,` depend-entry
805 /// depend-entry ::= depend-kind `->` ssa-id `:` type
806 static ParseResult
809  SmallVectorImpl<Type> &types, ArrayAttr &dependsArray) {
811  if (failed(parser.parseCommaSeparatedList([&]() {
812  StringRef keyword;
813  if (parser.parseKeyword(&keyword) || parser.parseArrow() ||
814  parser.parseOperand(operands.emplace_back()) ||
815  parser.parseColonType(types.emplace_back()))
816  return failure();
817  if (std::optional<ClauseTaskDepend> keywordDepend =
818  (symbolizeClauseTaskDepend(keyword)))
819  dependVec.emplace_back(
820  ClauseTaskDependAttr::get(parser.getContext(), *keywordDepend));
821  else
822  return failure();
823  return success();
824  })))
825  return failure();
826  SmallVector<Attribute> depends(dependVec.begin(), dependVec.end());
827  dependsArray = ArrayAttr::get(parser.getContext(), depends);
828  return success();
829 }
830 
831 /// Print Depend clause
833  OperandRange dependVars, TypeRange dependTypes,
834  std::optional<ArrayAttr> depends) {
835 
836  for (unsigned i = 0, e = depends->size(); i < e; ++i) {
837  if (i != 0)
838  p << ", ";
839  p << stringifyClauseTaskDepend(
840  llvm::cast<mlir::omp::ClauseTaskDependAttr>((*depends)[i])
841  .getValue())
842  << " -> " << dependVars[i] << " : " << dependTypes[i];
843  }
844 }
845 
846 /// Verifies Depend clause
847 static LogicalResult verifyDependVarList(Operation *op,
848  std::optional<ArrayAttr> depends,
849  OperandRange dependVars) {
850  if (!dependVars.empty()) {
851  if (!depends || depends->size() != dependVars.size())
852  return op->emitOpError() << "expected as many depend values"
853  " as depend variables";
854  } else {
855  if (depends && !depends->empty())
856  return op->emitOpError() << "unexpected depend values";
857  return success();
858  }
859 
860  return success();
861 }
862 
863 //===----------------------------------------------------------------------===//
864 // Parser, printer and verifier for Synchronization Hint (2.17.12)
865 //===----------------------------------------------------------------------===//
866 
867 /// Parses a Synchronization Hint clause. The value of hint is an integer
868 /// which is a combination of different hints from `omp_sync_hint_t`.
869 ///
870 /// hint-clause = `hint` `(` hint-value `)`
871 static ParseResult parseSynchronizationHint(OpAsmParser &parser,
872  IntegerAttr &hintAttr) {
873  StringRef hintKeyword;
874  int64_t hint = 0;
875  if (succeeded(parser.parseOptionalKeyword("none"))) {
876  hintAttr = IntegerAttr::get(parser.getBuilder().getI64Type(), 0);
877  return success();
878  }
879  auto parseKeyword = [&]() -> ParseResult {
880  if (failed(parser.parseKeyword(&hintKeyword)))
881  return failure();
882  if (hintKeyword == "uncontended")
883  hint |= 1;
884  else if (hintKeyword == "contended")
885  hint |= 2;
886  else if (hintKeyword == "nonspeculative")
887  hint |= 4;
888  else if (hintKeyword == "speculative")
889  hint |= 8;
890  else
891  return parser.emitError(parser.getCurrentLocation())
892  << hintKeyword << " is not a valid hint";
893  return success();
894  };
895  if (parser.parseCommaSeparatedList(parseKeyword))
896  return failure();
897  hintAttr = IntegerAttr::get(parser.getBuilder().getI64Type(), hint);
898  return success();
899 }
900 
901 /// Prints a Synchronization Hint clause
903  IntegerAttr hintAttr) {
904  int64_t hint = hintAttr.getInt();
905 
906  if (hint == 0) {
907  p << "none";
908  return;
909  }
910 
911  // Helper function to get n-th bit from the right end of `value`
912  auto bitn = [](int value, int n) -> bool { return value & (1 << n); };
913 
914  bool uncontended = bitn(hint, 0);
915  bool contended = bitn(hint, 1);
916  bool nonspeculative = bitn(hint, 2);
917  bool speculative = bitn(hint, 3);
918 
920  if (uncontended)
921  hints.push_back("uncontended");
922  if (contended)
923  hints.push_back("contended");
924  if (nonspeculative)
925  hints.push_back("nonspeculative");
926  if (speculative)
927  hints.push_back("speculative");
928 
929  llvm::interleaveComma(hints, p);
930 }
931 
932 /// Verifies a synchronization hint clause
933 static LogicalResult verifySynchronizationHint(Operation *op, uint64_t hint) {
934 
935  // Helper function to get n-th bit from the right end of `value`
936  auto bitn = [](int value, int n) -> bool { return value & (1 << n); };
937 
938  bool uncontended = bitn(hint, 0);
939  bool contended = bitn(hint, 1);
940  bool nonspeculative = bitn(hint, 2);
941  bool speculative = bitn(hint, 3);
942 
943  if (uncontended && contended)
944  return op->emitOpError() << "the hints omp_sync_hint_uncontended and "
945  "omp_sync_hint_contended cannot be combined";
946  if (nonspeculative && speculative)
947  return op->emitOpError() << "the hints omp_sync_hint_nonspeculative and "
948  "omp_sync_hint_speculative cannot be combined.";
949  return success();
950 }
951 
952 //===----------------------------------------------------------------------===//
953 // Parser, printer and verifier for Target
954 //===----------------------------------------------------------------------===//
955 
956 // Helper function to get bitwise AND of `value` and 'flag'
957 uint64_t mapTypeToBitFlag(uint64_t value,
958  llvm::omp::OpenMPOffloadMappingFlags flag) {
959  return value & llvm::to_underlying(flag);
960 }
961 
962 /// Parses a map_entries map type from a string format back into its numeric
963 /// value.
964 ///
965 /// map-clause = `map_clauses ( ( `(` `always, `? `close, `? `present, `? (
966 /// `to` | `from` | `delete` `)` )+ `)` )
967 static ParseResult parseMapClause(OpAsmParser &parser, IntegerAttr &mapType) {
968  llvm::omp::OpenMPOffloadMappingFlags mapTypeBits =
969  llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_NONE;
970 
971  // This simply verifies the correct keyword is read in, the
972  // keyword itself is stored inside of the operation
973  auto parseTypeAndMod = [&]() -> ParseResult {
974  StringRef mapTypeMod;
975  if (parser.parseKeyword(&mapTypeMod))
976  return failure();
977 
978  if (mapTypeMod == "always")
979  mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_ALWAYS;
980 
981  if (mapTypeMod == "implicit")
982  mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT;
983 
984  if (mapTypeMod == "close")
985  mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_CLOSE;
986 
987  if (mapTypeMod == "present")
988  mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_PRESENT;
989 
990  if (mapTypeMod == "to")
991  mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO;
992 
993  if (mapTypeMod == "from")
994  mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM;
995 
996  if (mapTypeMod == "tofrom")
997  mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO |
998  llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM;
999 
1000  if (mapTypeMod == "delete")
1001  mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_DELETE;
1002 
1003  return success();
1004  };
1005 
1006  if (parser.parseCommaSeparatedList(parseTypeAndMod))
1007  return failure();
1008 
1009  mapType = parser.getBuilder().getIntegerAttr(
1010  parser.getBuilder().getIntegerType(64, /*isSigned=*/false),
1011  llvm::to_underlying(mapTypeBits));
1012 
1013  return success();
1014 }
1015 
1016 /// Prints a map_entries map type from its numeric value out into its string
1017 /// format.
1019  IntegerAttr mapType) {
1020  uint64_t mapTypeBits = mapType.getUInt();
1021 
1022  bool emitAllocRelease = true;
1024 
1025  // handling of always, close, present placed at the beginning of the string
1026  // to aid readability
1027  if (mapTypeToBitFlag(mapTypeBits,
1028  llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_ALWAYS))
1029  mapTypeStrs.push_back("always");
1030  if (mapTypeToBitFlag(mapTypeBits,
1031  llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT))
1032  mapTypeStrs.push_back("implicit");
1033  if (mapTypeToBitFlag(mapTypeBits,
1034  llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_CLOSE))
1035  mapTypeStrs.push_back("close");
1036  if (mapTypeToBitFlag(mapTypeBits,
1037  llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_PRESENT))
1038  mapTypeStrs.push_back("present");
1039 
1040  // special handling of to/from/tofrom/delete and release/alloc, release +
1041  // alloc are the abscense of one of the other flags, whereas tofrom requires
1042  // both the to and from flag to be set.
1043  bool to = mapTypeToBitFlag(mapTypeBits,
1044  llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO);
1045  bool from = mapTypeToBitFlag(
1046  mapTypeBits, llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM);
1047  if (to && from) {
1048  emitAllocRelease = false;
1049  mapTypeStrs.push_back("tofrom");
1050  } else if (from) {
1051  emitAllocRelease = false;
1052  mapTypeStrs.push_back("from");
1053  } else if (to) {
1054  emitAllocRelease = false;
1055  mapTypeStrs.push_back("to");
1056  }
1057  if (mapTypeToBitFlag(mapTypeBits,
1058  llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_DELETE)) {
1059  emitAllocRelease = false;
1060  mapTypeStrs.push_back("delete");
1061  }
1062  if (emitAllocRelease)
1063  mapTypeStrs.push_back("exit_release_or_enter_alloc");
1064 
1065  for (unsigned int i = 0; i < mapTypeStrs.size(); ++i) {
1066  p << mapTypeStrs[i];
1067  if (i + 1 < mapTypeStrs.size()) {
1068  p << ", ";
1069  }
1070  }
1071 }
1072 
1073 static ParseResult parseMembersIndex(OpAsmParser &parser,
1074  DenseIntElementsAttr &membersIdx) {
1075  SmallVector<APInt> values;
1076  int64_t value;
1077  int64_t shape[2] = {0, 0};
1078  unsigned shapeTmp = 0;
1079  auto parseIndices = [&]() -> ParseResult {
1080  if (parser.parseInteger(value))
1081  return failure();
1082  shapeTmp++;
1083  values.push_back(APInt(32, value));
1084  return success();
1085  };
1086 
1087  do {
1088  if (failed(parser.parseLSquare()))
1089  return failure();
1090 
1091  if (parser.parseCommaSeparatedList(parseIndices))
1092  return failure();
1093 
1094  if (failed(parser.parseRSquare()))
1095  return failure();
1096 
1097  // Only set once, if any indices are not the same size
1098  // we error out in the next check as that's unsupported
1099  if (shape[1] == 0)
1100  shape[1] = shapeTmp;
1101 
1102  // Verify that the recently parsed list is equal to the
1103  // first one we parsed, they must be equal lengths to
1104  // keep the rectangular shape DenseIntElementsAttr
1105  // requires
1106  if (shapeTmp != shape[1])
1107  return failure();
1108 
1109  shapeTmp = 0;
1110  shape[0]++;
1111  } while (succeeded(parser.parseOptionalComma()));
1112 
1113  if (!values.empty()) {
1114  ShapedType valueType =
1115  VectorType::get(shape, IntegerType::get(parser.getContext(), 32));
1116  membersIdx = DenseIntElementsAttr::get(valueType, values);
1117  }
1118 
1119  return success();
1120 }
1121 
1122 static void printMembersIndex(OpAsmPrinter &p, MapInfoOp op,
1123  DenseIntElementsAttr membersIdx) {
1124  llvm::ArrayRef<int64_t> shape = membersIdx.getShapedType().getShape();
1125  assert(shape.size() <= 2);
1126 
1127  if (!membersIdx)
1128  return;
1129 
1130  for (int i = 0; i < shape[0]; ++i) {
1131  p << "[";
1132  int rowOffset = i * shape[1];
1133  for (int j = 0; j < shape[1]; ++j) {
1134  p << membersIdx.getValues<int32_t>()[rowOffset + j];
1135  if ((j + 1) < shape[1])
1136  p << ",";
1137  }
1138  p << "]";
1139 
1140  if ((i + 1) < shape[0])
1141  p << ", ";
1142  }
1143 }
1144 
1145 static ParseResult
1148  SmallVectorImpl<Type> &mapOperandTypes) {
1151  Type argType;
1152  auto parseEntries = [&]() -> ParseResult {
1153  if (parser.parseOperand(arg))
1154  return failure();
1155  if (succeeded(parser.parseOptionalArrow()) && parser.parseOperand(blockArg))
1156  return failure();
1157  mapOperands.push_back(arg);
1158  return success();
1159  };
1160 
1161  auto parseTypes = [&]() -> ParseResult {
1162  if (parser.parseType(argType))
1163  return failure();
1164  mapOperandTypes.push_back(argType);
1165  return success();
1166  };
1167 
1168  if (parser.parseCommaSeparatedList(parseEntries))
1169  return failure();
1170 
1171  if (parser.parseColon())
1172  return failure();
1173 
1174  if (parser.parseCommaSeparatedList(parseTypes))
1175  return failure();
1176 
1177  return success();
1178 }
1179 
1181  OperandRange mapOperands,
1182  TypeRange mapOperandTypes) {
1183  // Get pointer to the region if this is an omp.target, because printing map
1184  // clauses for that operation has to also show the correspondence of each
1185  // variable to the corresponding block argument.
1186  Block *entryBlock = isa<TargetOp>(op) ? &op->getRegion(0).front() : nullptr;
1187  unsigned argIndex = 0;
1188 
1189  for (const auto &mapOp : mapOperands) {
1190  p << mapOp;
1191  if (entryBlock) {
1192  const auto &blockArg = entryBlock->getArgument(argIndex);
1193  p << " -> " << blockArg;
1194  }
1195  argIndex++;
1196  if (argIndex < mapOperands.size())
1197  p << ", ";
1198  }
1199  p << " : ";
1200 
1201  argIndex = 0;
1202  for (const auto &mapType : mapOperandTypes) {
1203  p << mapType;
1204  argIndex++;
1205  if (argIndex < mapOperands.size())
1206  p << ", ";
1207  }
1208 }
1209 
1210 static ParseResult parsePrivateList(
1211  OpAsmParser &parser,
1213  SmallVectorImpl<Type> &privateOperandTypes, ArrayAttr &privatizerSymbols) {
1214  SmallVector<SymbolRefAttr> privateSymRefs;
1215  SmallVector<OpAsmParser::Argument> regionPrivateArgs;
1216 
1217  if (failed(parser.parseCommaSeparatedList([&]() {
1218  if (parser.parseAttribute(privateSymRefs.emplace_back()) ||
1219  parser.parseOperand(privateOperands.emplace_back()) ||
1220  parser.parseArrow() ||
1221  parser.parseArgument(regionPrivateArgs.emplace_back()) ||
1222  parser.parseColonType(privateOperandTypes.emplace_back()))
1223  return failure();
1224  return success();
1225  })))
1226  return failure();
1227 
1228  SmallVector<Attribute> privateSymAttrs(privateSymRefs.begin(),
1229  privateSymRefs.end());
1230  privatizerSymbols = ArrayAttr::get(parser.getContext(), privateSymAttrs);
1231 
1232  return success();
1233 }
1234 
1236  ValueRange privateVarOperands,
1237  TypeRange privateVarTypes,
1238  ArrayAttr privatizerSymbols) {
1239  // TODO: Remove target-specific logic from this function.
1240  auto targetOp = mlir::dyn_cast<mlir::omp::TargetOp>(op);
1241  assert(targetOp);
1242 
1243  auto &region = op->getRegion(0);
1244  auto *argsBegin = region.front().getArguments().begin();
1245  MutableArrayRef argsSubrange(argsBegin + targetOp.getMapOperands().size(),
1246  argsBegin + targetOp.getMapOperands().size() +
1247  privateVarTypes.size());
1248  mlir::SmallVector<bool> isByRefVec;
1249  isByRefVec.resize(privateVarTypes.size(), false);
1250  DenseBoolArrayAttr isByRef =
1251  DenseBoolArrayAttr::get(op->getContext(), isByRefVec);
1252 
1254  p, op, argsSubrange, /*clauseName=*/llvm::StringRef{}, privateVarOperands,
1255  privateVarTypes, isByRef, privatizerSymbols);
1256 }
1257 
1259  VariableCaptureKindAttr mapCaptureType) {
1260  std::string typeCapStr;
1261  llvm::raw_string_ostream typeCap(typeCapStr);
1262  if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::ByRef)
1263  typeCap << "ByRef";
1264  if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::ByCopy)
1265  typeCap << "ByCopy";
1266  if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::VLAType)
1267  typeCap << "VLAType";
1268  if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::This)
1269  typeCap << "This";
1270  p << typeCap.str();
1271 }
1272 
1273 static ParseResult parseCaptureType(OpAsmParser &parser,
1274  VariableCaptureKindAttr &mapCapture) {
1275  StringRef mapCaptureKey;
1276  if (parser.parseKeyword(&mapCaptureKey))
1277  return failure();
1278 
1279  if (mapCaptureKey == "This")
1281  parser.getContext(), mlir::omp::VariableCaptureKind::This);
1282  if (mapCaptureKey == "ByRef")
1284  parser.getContext(), mlir::omp::VariableCaptureKind::ByRef);
1285  if (mapCaptureKey == "ByCopy")
1287  parser.getContext(), mlir::omp::VariableCaptureKind::ByCopy);
1288  if (mapCaptureKey == "VLAType")
1290  parser.getContext(), mlir::omp::VariableCaptureKind::VLAType);
1291 
1292  return success();
1293 }
1294 
1295 static LogicalResult verifyMapClause(Operation *op, OperandRange mapOperands) {
1298 
1299  for (auto mapOp : mapOperands) {
1300  if (!mapOp.getDefiningOp())
1301  emitError(op->getLoc(), "missing map operation");
1302 
1303  if (auto mapInfoOp =
1304  mlir::dyn_cast<mlir::omp::MapInfoOp>(mapOp.getDefiningOp())) {
1305  if (!mapInfoOp.getMapType().has_value())
1306  emitError(op->getLoc(), "missing map type for map operand");
1307 
1308  if (!mapInfoOp.getMapCaptureType().has_value())
1309  emitError(op->getLoc(), "missing map capture type for map operand");
1310 
1311  uint64_t mapTypeBits = mapInfoOp.getMapType().value();
1312 
1313  bool to = mapTypeToBitFlag(
1314  mapTypeBits, llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO);
1315  bool from = mapTypeToBitFlag(
1316  mapTypeBits, llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM);
1317  bool del = mapTypeToBitFlag(
1318  mapTypeBits, llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_DELETE);
1319 
1320  bool always = mapTypeToBitFlag(
1321  mapTypeBits, llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_ALWAYS);
1322  bool close = mapTypeToBitFlag(
1323  mapTypeBits, llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_CLOSE);
1324  bool implicit = mapTypeToBitFlag(
1325  mapTypeBits, llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT);
1326 
1327  if ((isa<TargetDataOp>(op) || isa<TargetOp>(op)) && del)
1328  return emitError(op->getLoc(),
1329  "to, from, tofrom and alloc map types are permitted");
1330 
1331  if (isa<TargetEnterDataOp>(op) && (from || del))
1332  return emitError(op->getLoc(), "to and alloc map types are permitted");
1333 
1334  if (isa<TargetExitDataOp>(op) && to)
1335  return emitError(op->getLoc(),
1336  "from, release and delete map types are permitted");
1337 
1338  if (isa<TargetUpdateOp>(op)) {
1339  if (del) {
1340  return emitError(op->getLoc(),
1341  "at least one of to or from map types must be "
1342  "specified, other map types are not permitted");
1343  }
1344 
1345  if (!to && !from) {
1346  return emitError(op->getLoc(),
1347  "at least one of to or from map types must be "
1348  "specified, other map types are not permitted");
1349  }
1350 
1351  auto updateVar = mapInfoOp.getVarPtr();
1352 
1353  if ((to && from) || (to && updateFromVars.contains(updateVar)) ||
1354  (from && updateToVars.contains(updateVar))) {
1355  return emitError(
1356  op->getLoc(),
1357  "either to or from map types can be specified, not both");
1358  }
1359 
1360  if (always || close || implicit) {
1361  return emitError(
1362  op->getLoc(),
1363  "present, mapper and iterator map type modifiers are permitted");
1364  }
1365 
1366  to ? updateToVars.insert(updateVar) : updateFromVars.insert(updateVar);
1367  }
1368  } else {
1369  emitError(op->getLoc(), "map argument is not a map entry operation");
1370  }
1371  }
1372 
1373  return success();
1374 }
1375 
1376 //===----------------------------------------------------------------------===//
1377 // TargetDataOp
1378 //===----------------------------------------------------------------------===//
1379 
1380 void TargetDataOp::build(OpBuilder &builder, OperationState &state,
1381  const TargetDataClauseOps &clauses) {
1382  TargetDataOp::build(builder, state, clauses.ifVar, clauses.deviceVar,
1383  clauses.useDevicePtrVars, clauses.useDeviceAddrVars,
1384  clauses.mapVars);
1385 }
1386 
1387 LogicalResult TargetDataOp::verify() {
1388  if (getMapOperands().empty() && getUseDevicePtr().empty() &&
1389  getUseDeviceAddr().empty()) {
1390  return ::emitError(this->getLoc(), "At least one of map, useDevicePtr, or "
1391  "useDeviceAddr operand must be present");
1392  }
1393  return verifyMapClause(*this, getMapOperands());
1394 }
1395 
1396 //===----------------------------------------------------------------------===//
1397 // TargetEnterDataOp
1398 //===----------------------------------------------------------------------===//
1399 
1400 void TargetEnterDataOp::build(
1401  OpBuilder &builder, OperationState &state,
1402  const TargetEnterExitUpdateDataClauseOps &clauses) {
1403  MLIRContext *ctx = builder.getContext();
1404  TargetEnterDataOp::build(builder, state, clauses.ifVar, clauses.deviceVar,
1405  makeArrayAttr(ctx, clauses.dependTypeAttrs),
1406  clauses.dependVars, clauses.nowaitAttr,
1407  clauses.mapVars);
1408 }
1409 
1410 LogicalResult TargetEnterDataOp::verify() {
1411  LogicalResult verifyDependVars =
1412  verifyDependVarList(*this, getDepends(), getDependVars());
1413  return failed(verifyDependVars) ? verifyDependVars
1414  : verifyMapClause(*this, getMapOperands());
1415 }
1416 
1417 //===----------------------------------------------------------------------===//
1418 // TargetExitDataOp
1419 //===----------------------------------------------------------------------===//
1420 
1421 void TargetExitDataOp::build(
1422  OpBuilder &builder, OperationState &state,
1423  const TargetEnterExitUpdateDataClauseOps &clauses) {
1424  MLIRContext *ctx = builder.getContext();
1425  TargetExitDataOp::build(builder, state, clauses.ifVar, clauses.deviceVar,
1426  makeArrayAttr(ctx, clauses.dependTypeAttrs),
1427  clauses.dependVars, clauses.nowaitAttr,
1428  clauses.mapVars);
1429 }
1430 
1431 LogicalResult TargetExitDataOp::verify() {
1432  LogicalResult verifyDependVars =
1433  verifyDependVarList(*this, getDepends(), getDependVars());
1434  return failed(verifyDependVars) ? verifyDependVars
1435  : verifyMapClause(*this, getMapOperands());
1436 }
1437 
1438 //===----------------------------------------------------------------------===//
1439 // TargetUpdateOp
1440 //===----------------------------------------------------------------------===//
1441 
1442 void TargetUpdateOp::build(OpBuilder &builder, OperationState &state,
1443  const TargetEnterExitUpdateDataClauseOps &clauses) {
1444  MLIRContext *ctx = builder.getContext();
1445  TargetUpdateOp::build(builder, state, clauses.ifVar, clauses.deviceVar,
1446  makeArrayAttr(ctx, clauses.dependTypeAttrs),
1447  clauses.dependVars, clauses.nowaitAttr,
1448  clauses.mapVars);
1449 }
1450 
1451 LogicalResult TargetUpdateOp::verify() {
1452  LogicalResult verifyDependVars =
1453  verifyDependVarList(*this, getDepends(), getDependVars());
1454  return failed(verifyDependVars) ? verifyDependVars
1455  : verifyMapClause(*this, getMapOperands());
1456 }
1457 
1458 //===----------------------------------------------------------------------===//
1459 // TargetOp
1460 //===----------------------------------------------------------------------===//
1461 
1462 void TargetOp::build(OpBuilder &builder, OperationState &state,
1463  const TargetClauseOps &clauses) {
1464  MLIRContext *ctx = builder.getContext();
1465  // TODO Store clauses in op: allocateVars, allocatorVars, inReductionVars,
1466  // inReduceVarByRef, inReductionDeclSymbols, reductionVars, reduceVarByRef,
1467  // reductionDeclSymbols.
1468  TargetOp::build(
1469  builder, state, clauses.ifVar, clauses.deviceVar, clauses.threadLimitVar,
1470  makeArrayAttr(ctx, clauses.dependTypeAttrs), clauses.dependVars,
1471  clauses.nowaitAttr, clauses.isDevicePtrVars, clauses.hasDeviceAddrVars,
1472  clauses.mapVars, clauses.privateVars,
1473  makeArrayAttr(ctx, clauses.privatizers));
1474 }
1475 
1476 LogicalResult TargetOp::verify() {
1477  LogicalResult verifyDependVars =
1478  verifyDependVarList(*this, getDepends(), getDependVars());
1479  return failed(verifyDependVars) ? verifyDependVars
1480  : verifyMapClause(*this, getMapOperands());
1481 }
1482 
1483 //===----------------------------------------------------------------------===//
1484 // ParallelOp
1485 //===----------------------------------------------------------------------===//
1486 
1487 void ParallelOp::build(OpBuilder &builder, OperationState &state,
1488  ArrayRef<NamedAttribute> attributes) {
1489  ParallelOp::build(
1490  builder, state, /*if_expr=*/nullptr, /*num_threads_var=*/nullptr,
1491  /*allocate_vars=*/ValueRange(), /*allocators_vars=*/ValueRange(),
1492  /*reduction_vars=*/ValueRange(), /*reduction_vars_byref=*/nullptr,
1493  /*reductions=*/nullptr, /*proc_bind_val=*/nullptr,
1494  /*private_vars=*/ValueRange(), /*privatizers=*/nullptr);
1495  state.addAttributes(attributes);
1496 }
1497 
1498 void ParallelOp::build(OpBuilder &builder, OperationState &state,
1499  const ParallelClauseOps &clauses) {
1500  MLIRContext *ctx = builder.getContext();
1501 
1502  ParallelOp::build(builder, state, clauses.ifVar, clauses.numThreadsVar,
1503  clauses.allocateVars, clauses.allocatorVars,
1504  clauses.reductionVars,
1505  makeDenseBoolArrayAttr(ctx, clauses.reductionVarsByRef),
1506  makeArrayAttr(ctx, clauses.reductionDeclSymbols),
1507  clauses.procBindKindAttr, clauses.privateVars,
1508  makeArrayAttr(ctx, clauses.privatizers));
1509 }
1510 
1511 template <typename OpType>
1512 static LogicalResult verifyPrivateVarList(OpType &op) {
1513  auto privateVars = op.getPrivateVars();
1514  auto privatizers = op.getPrivatizersAttr();
1515 
1516  if (privateVars.empty() && (privatizers == nullptr || privatizers.empty()))
1517  return success();
1518 
1519  auto numPrivateVars = privateVars.size();
1520  auto numPrivatizers = (privatizers == nullptr) ? 0 : privatizers.size();
1521 
1522  if (numPrivateVars != numPrivatizers)
1523  return op.emitError() << "inconsistent number of private variables and "
1524  "privatizer op symbols, private vars: "
1525  << numPrivateVars
1526  << " vs. privatizer op symbols: " << numPrivatizers;
1527 
1528  for (auto privateVarInfo : llvm::zip_equal(privateVars, privatizers)) {
1529  Type varType = std::get<0>(privateVarInfo).getType();
1530  SymbolRefAttr privatizerSym =
1531  cast<SymbolRefAttr>(std::get<1>(privateVarInfo));
1532  PrivateClauseOp privatizerOp =
1533  SymbolTable::lookupNearestSymbolFrom<PrivateClauseOp>(op,
1534  privatizerSym);
1535 
1536  if (privatizerOp == nullptr)
1537  return op.emitError() << "failed to lookup privatizer op with symbol: '"
1538  << privatizerSym << "'";
1539 
1540  Type privatizerType = privatizerOp.getType();
1541 
1542  if (varType != privatizerType)
1543  return op.emitError()
1544  << "type mismatch between a "
1545  << (privatizerOp.getDataSharingType() ==
1546  DataSharingClauseType::Private
1547  ? "private"
1548  : "firstprivate")
1549  << " variable and its privatizer op, var type: " << varType
1550  << " vs. privatizer op type: " << privatizerType;
1551  }
1552 
1553  return success();
1554 }
1555 
1556 LogicalResult ParallelOp::verify() {
1557  // Check that it is a valid loop wrapper if it's taking that role.
1558  if (isa<DistributeOp>((*this)->getParentOp())) {
1559  if (!isWrapper())
1560  return emitOpError() << "must take a loop wrapper role if nested inside "
1561  "of 'omp.distribute'";
1562 
1563  if (LoopWrapperInterface nested = getNestedWrapper()) {
1564  // Check for the allowed leaf constructs that may appear in a composite
1565  // construct directly after PARALLEL.
1566  if (!isa<WsloopOp>(nested))
1567  return emitError() << "only supported nested wrapper is 'omp.wsloop'";
1568  } else {
1569  return emitOpError() << "must not wrap an 'omp.loop_nest' directly";
1570  }
1571  }
1572 
1573  if (getAllocateVars().size() != getAllocatorsVars().size())
1574  return emitError(
1575  "expected equal sizes for allocate and allocator variables");
1576 
1577  if (failed(verifyPrivateVarList(*this)))
1578  return failure();
1579 
1580  return verifyReductionVarList(*this, getReductions(), getReductionVars(),
1581  getReductionVarsByref());
1582 }
1583 
1584 //===----------------------------------------------------------------------===//
1585 // TeamsOp
1586 //===----------------------------------------------------------------------===//
1587 
1589  while ((op = op->getParentOp()))
1590  if (isa<OpenMPDialect>(op->getDialect()))
1591  return false;
1592  return true;
1593 }
1594 
1595 void TeamsOp::build(OpBuilder &builder, OperationState &state,
1596  const TeamsClauseOps &clauses) {
1597  MLIRContext *ctx = builder.getContext();
1598  // TODO Store clauses in op: privateVars, privatizers.
1599  TeamsOp::build(builder, state, clauses.numTeamsLowerVar,
1600  clauses.numTeamsUpperVar, clauses.ifVar,
1601  clauses.threadLimitVar, clauses.allocateVars,
1602  clauses.allocatorVars, clauses.reductionVars,
1603  makeDenseBoolArrayAttr(ctx, clauses.reductionVarsByRef),
1604  makeArrayAttr(ctx, clauses.reductionDeclSymbols));
1605 }
1606 
1607 LogicalResult TeamsOp::verify() {
1608  // Check parent region
1609  // TODO If nested inside of a target region, also check that it does not
1610  // contain any statements, declarations or directives other than this
1611  // omp.teams construct. The issue is how to support the initialization of
1612  // this operation's own arguments (allow SSA values across omp.target?).
1613  Operation *op = getOperation();
1614  if (!isa<TargetOp>(op->getParentOp()) &&
1616  return emitError("expected to be nested inside of omp.target or not nested "
1617  "in any OpenMP dialect operations");
1618 
1619  // Check for num_teams clause restrictions
1620  if (auto numTeamsLowerBound = getNumTeamsLower()) {
1621  auto numTeamsUpperBound = getNumTeamsUpper();
1622  if (!numTeamsUpperBound)
1623  return emitError("expected num_teams upper bound to be defined if the "
1624  "lower bound is defined");
1625  if (numTeamsLowerBound.getType() != numTeamsUpperBound.getType())
1626  return emitError(
1627  "expected num_teams upper bound and lower bound to be the same type");
1628  }
1629 
1630  // Check for allocate clause restrictions
1631  if (getAllocateVars().size() != getAllocatorsVars().size())
1632  return emitError(
1633  "expected equal sizes for allocate and allocator variables");
1634 
1635  return verifyReductionVarList(*this, getReductions(), getReductionVars(),
1636  getReductionVarsByref());
1637 }
1638 
1639 //===----------------------------------------------------------------------===//
1640 // SectionsOp
1641 //===----------------------------------------------------------------------===//
1642 
1643 void SectionsOp::build(OpBuilder &builder, OperationState &state,
1644  const SectionsClauseOps &clauses) {
1645  MLIRContext *ctx = builder.getContext();
1646  // TODO Store clauses in op: privateVars, privatizers.
1647  SectionsOp::build(builder, state, clauses.reductionVars,
1648  makeDenseBoolArrayAttr(ctx, clauses.reductionVarsByRef),
1649  makeArrayAttr(ctx, clauses.reductionDeclSymbols),
1650  clauses.allocateVars, clauses.allocatorVars,
1651  clauses.nowaitAttr);
1652 }
1653 
1654 LogicalResult SectionsOp::verify() {
1655  if (getAllocateVars().size() != getAllocatorsVars().size())
1656  return emitError(
1657  "expected equal sizes for allocate and allocator variables");
1658 
1659  return verifyReductionVarList(*this, getReductions(), getReductionVars(),
1660  getReductionVarsByref());
1661 }
1662 
1663 LogicalResult SectionsOp::verifyRegions() {
1664  for (auto &inst : *getRegion().begin()) {
1665  if (!(isa<SectionOp>(inst) || isa<TerminatorOp>(inst))) {
1666  return emitOpError()
1667  << "expected omp.section op or terminator op inside region";
1668  }
1669  }
1670 
1671  return success();
1672 }
1673 
1674 //===----------------------------------------------------------------------===//
1675 // SingleOp
1676 //===----------------------------------------------------------------------===//
1677 
1678 void SingleOp::build(OpBuilder &builder, OperationState &state,
1679  const SingleClauseOps &clauses) {
1680  MLIRContext *ctx = builder.getContext();
1681  // TODO Store clauses in op: privateVars, privatizers.
1682  SingleOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
1683  clauses.copyprivateVars,
1684  makeArrayAttr(ctx, clauses.copyprivateFuncs),
1685  clauses.nowaitAttr);
1686 }
1687 
1688 LogicalResult SingleOp::verify() {
1689  // Check for allocate clause restrictions
1690  if (getAllocateVars().size() != getAllocatorsVars().size())
1691  return emitError(
1692  "expected equal sizes for allocate and allocator variables");
1693 
1694  return verifyCopyPrivateVarList(*this, getCopyprivateVars(),
1695  getCopyprivateFuncs());
1696 }
1697 
1698 //===----------------------------------------------------------------------===//
1699 // WsloopOp
1700 //===----------------------------------------------------------------------===//
1701 
1702 ParseResult
1703 parseWsloop(OpAsmParser &parser, Region &region,
1705  SmallVectorImpl<Type> &reductionTypes,
1706  DenseBoolArrayAttr &reductionByRef, ArrayAttr &reductionSymbols) {
1707  // Parse an optional reduction clause
1709  if (succeeded(parser.parseOptionalKeyword("reduction"))) {
1710  if (failed(parseClauseWithRegionArgs(parser, region, reductionOperands,
1711  reductionTypes, reductionByRef,
1712  reductionSymbols, privates)))
1713  return failure();
1714  }
1715  return parser.parseRegion(region, privates);
1716 }
1717 
1719  ValueRange reductionOperands, TypeRange reductionTypes,
1720  DenseBoolArrayAttr isByRef, ArrayAttr reductionSymbols) {
1721  if (reductionSymbols) {
1722  auto reductionArgs = region.front().getArguments();
1723  printClauseWithRegionArgs(p, op, reductionArgs, "reduction",
1724  reductionOperands, reductionTypes, isByRef,
1725  reductionSymbols);
1726  }
1727  p.printRegion(region, /*printEntryBlockArgs=*/false);
1728 }
1729 
1730 void WsloopOp::build(OpBuilder &builder, OperationState &state,
1731  ArrayRef<NamedAttribute> attributes) {
1732  build(builder, state, /*linear_vars=*/ValueRange(),
1733  /*linear_step_vars=*/ValueRange(), /*reduction_vars=*/ValueRange(),
1734  /*reduction_vars_byref=*/nullptr,
1735  /*reductions=*/nullptr, /*schedule_val=*/nullptr,
1736  /*schedule_chunk_var=*/nullptr, /*schedule_modifier=*/nullptr,
1737  /*simd_modifier=*/false, /*nowait=*/false,
1738  /*ordered_val=*/nullptr, /*order_val=*/nullptr,
1739  /*order_modifier=*/nullptr);
1740  state.addAttributes(attributes);
1741 }
1742 
1743 void WsloopOp::build(OpBuilder &builder, OperationState &state,
1744  const WsloopClauseOps &clauses) {
1745  MLIRContext *ctx = builder.getContext();
1746  // TODO: Store clauses in op: allocateVars, allocatorVars, privateVars,
1747  // privatizers.
1748  WsloopOp::build(builder, state, clauses.linearVars, clauses.linearStepVars,
1749  clauses.reductionVars,
1750  makeDenseBoolArrayAttr(ctx, clauses.reductionVarsByRef),
1751  makeArrayAttr(ctx, clauses.reductionDeclSymbols),
1752  clauses.scheduleValAttr, clauses.scheduleChunkVar,
1753  clauses.scheduleModAttr, clauses.scheduleSimdAttr,
1754  clauses.nowaitAttr, clauses.orderedAttr, clauses.orderAttr,
1755  clauses.orderModAttr);
1756 }
1757 
1758 LogicalResult WsloopOp::verify() {
1759  if (!isWrapper())
1760  return emitOpError() << "must be a loop wrapper";
1761 
1762  if (LoopWrapperInterface nested = getNestedWrapper()) {
1763  // Check for the allowed leaf constructs that may appear in a composite
1764  // construct directly after DO/FOR.
1765  if (!isa<SimdOp>(nested))
1766  return emitError() << "only supported nested wrapper is 'omp.simd'";
1767  }
1768 
1769  return verifyReductionVarList(*this, getReductions(), getReductionVars(),
1770  getReductionVarsByref());
1771 }
1772 
1773 //===----------------------------------------------------------------------===//
1774 // Simd construct [2.9.3.1]
1775 //===----------------------------------------------------------------------===//
1776 
1777 void SimdOp::build(OpBuilder &builder, OperationState &state,
1778  const SimdClauseOps &clauses) {
1779  MLIRContext *ctx = builder.getContext();
1780  // TODO Store clauses in op: privateVars, privatizers, reductionVars,
1781  // reduceVarByRef, reductionDeclSymbols.
1782  SimdOp::build(builder, state, clauses.alignedVars,
1783  makeArrayAttr(ctx, clauses.alignmentAttrs), clauses.ifVar,
1784  clauses.nontemporalVars, clauses.orderAttr,
1785  clauses.orderModAttr, clauses.safelenAttr, clauses.simdlenAttr);
1786 }
1787 
1788 LogicalResult SimdOp::verify() {
1789  if (getSimdlen().has_value() && getSafelen().has_value() &&
1790  getSimdlen().value() > getSafelen().value())
1791  return emitOpError()
1792  << "simdlen clause and safelen clause are both present, but the "
1793  "simdlen value is not less than or equal to safelen value";
1794 
1795  if (verifyAlignedClause(*this, getAlignmentValues(), getAlignedVars())
1796  .failed())
1797  return failure();
1798 
1799  if (verifyNontemporalClause(*this, getNontemporalVars()).failed())
1800  return failure();
1801 
1802  if (!isWrapper())
1803  return emitOpError() << "must be a loop wrapper";
1804 
1805  if (getNestedWrapper())
1806  return emitOpError() << "must wrap an 'omp.loop_nest' directly";
1807 
1808  return success();
1809 }
1810 
1811 //===----------------------------------------------------------------------===//
1812 // Distribute construct [2.9.4.1]
1813 //===----------------------------------------------------------------------===//
1814 
1815 void DistributeOp::build(OpBuilder &builder, OperationState &state,
1816  const DistributeClauseOps &clauses) {
1817  // TODO Store clauses in op: privateVars, privatizers.
1818  DistributeOp::build(builder, state, clauses.distScheduleStaticAttr,
1819  clauses.distScheduleChunkSizeVar, clauses.allocateVars,
1820  clauses.allocatorVars, clauses.orderAttr,
1821  clauses.orderModAttr);
1822 }
1823 
1824 LogicalResult DistributeOp::verify() {
1825  if (this->getChunkSize() && !this->getDistScheduleStatic())
1826  return emitOpError() << "chunk size set without "
1827  "dist_schedule_static being present";
1828 
1829  if (getAllocateVars().size() != getAllocatorsVars().size())
1830  return emitError(
1831  "expected equal sizes for allocate and allocator variables");
1832 
1833  if (!isWrapper())
1834  return emitOpError() << "must be a loop wrapper";
1835 
1836  if (LoopWrapperInterface nested = getNestedWrapper()) {
1837  // Check for the allowed leaf constructs that may appear in a composite
1838  // construct directly after DISTRIBUTE.
1839  if (!isa<ParallelOp, SimdOp>(nested))
1840  return emitError() << "only supported nested wrappers are 'omp.parallel' "
1841  "and 'omp.simd'";
1842  }
1843 
1844  return success();
1845 }
1846 
1847 //===----------------------------------------------------------------------===//
1848 // DeclareReductionOp
1849 //===----------------------------------------------------------------------===//
1850 
1851 static ParseResult parseAtomicReductionRegion(OpAsmParser &parser,
1852  Region &region) {
1853  if (parser.parseOptionalKeyword("atomic"))
1854  return success();
1855  return parser.parseRegion(region);
1856 }
1857 
1859  DeclareReductionOp op, Region &region) {
1860  if (region.empty())
1861  return;
1862  printer << "atomic ";
1863  printer.printRegion(region);
1864 }
1865 
1866 static ParseResult parseCleanupReductionRegion(OpAsmParser &parser,
1867  Region &region) {
1868  if (parser.parseOptionalKeyword("cleanup"))
1869  return success();
1870  return parser.parseRegion(region);
1871 }
1872 
1874  DeclareReductionOp op, Region &region) {
1875  if (region.empty())
1876  return;
1877  printer << "cleanup ";
1878  printer.printRegion(region);
1879 }
1880 
1881 LogicalResult DeclareReductionOp::verifyRegions() {
1882  if (getInitializerRegion().empty())
1883  return emitOpError() << "expects non-empty initializer region";
1884  Block &initializerEntryBlock = getInitializerRegion().front();
1885  if (initializerEntryBlock.getNumArguments() != 1 ||
1886  initializerEntryBlock.getArgument(0).getType() != getType()) {
1887  return emitOpError() << "expects initializer region with one argument "
1888  "of the reduction type";
1889  }
1890 
1891  for (YieldOp yieldOp : getInitializerRegion().getOps<YieldOp>()) {
1892  if (yieldOp.getResults().size() != 1 ||
1893  yieldOp.getResults().getTypes()[0] != getType())
1894  return emitOpError() << "expects initializer region to yield a value "
1895  "of the reduction type";
1896  }
1897 
1898  if (getReductionRegion().empty())
1899  return emitOpError() << "expects non-empty reduction region";
1900  Block &reductionEntryBlock = getReductionRegion().front();
1901  if (reductionEntryBlock.getNumArguments() != 2 ||
1902  reductionEntryBlock.getArgumentTypes()[0] !=
1903  reductionEntryBlock.getArgumentTypes()[1] ||
1904  reductionEntryBlock.getArgumentTypes()[0] != getType())
1905  return emitOpError() << "expects reduction region with two arguments of "
1906  "the reduction type";
1907  for (YieldOp yieldOp : getReductionRegion().getOps<YieldOp>()) {
1908  if (yieldOp.getResults().size() != 1 ||
1909  yieldOp.getResults().getTypes()[0] != getType())
1910  return emitOpError() << "expects reduction region to yield a value "
1911  "of the reduction type";
1912  }
1913 
1914  if (!getAtomicReductionRegion().empty()) {
1915  Block &atomicReductionEntryBlock = getAtomicReductionRegion().front();
1916  if (atomicReductionEntryBlock.getNumArguments() != 2 ||
1917  atomicReductionEntryBlock.getArgumentTypes()[0] !=
1918  atomicReductionEntryBlock.getArgumentTypes()[1])
1919  return emitOpError() << "expects atomic reduction region with two "
1920  "arguments of the same type";
1921  auto ptrType = llvm::dyn_cast<PointerLikeType>(
1922  atomicReductionEntryBlock.getArgumentTypes()[0]);
1923  if (!ptrType ||
1924  (ptrType.getElementType() && ptrType.getElementType() != getType()))
1925  return emitOpError() << "expects atomic reduction region arguments to "
1926  "be accumulators containing the reduction type";
1927  }
1928 
1929  if (getCleanupRegion().empty())
1930  return success();
1931  Block &cleanupEntryBlock = getCleanupRegion().front();
1932  if (cleanupEntryBlock.getNumArguments() != 1 ||
1933  cleanupEntryBlock.getArgument(0).getType() != getType())
1934  return emitOpError() << "expects cleanup region with one argument "
1935  "of the reduction type";
1936 
1937  return success();
1938 }
1939 
1940 //===----------------------------------------------------------------------===//
1941 // TaskOp
1942 //===----------------------------------------------------------------------===//
1943 
1944 void TaskOp::build(OpBuilder &builder, OperationState &state,
1945  const TaskClauseOps &clauses) {
1946  MLIRContext *ctx = builder.getContext();
1947  // TODO Store clauses in op: privateVars, privatizers.
1948  TaskOp::build(
1949  builder, state, clauses.ifVar, clauses.finalVar, clauses.untiedAttr,
1950  clauses.mergeableAttr, clauses.inReductionVars,
1951  makeDenseBoolArrayAttr(ctx, clauses.inReductionVarsByRef),
1952  makeArrayAttr(ctx, clauses.inReductionDeclSymbols), clauses.priorityVar,
1953  makeArrayAttr(ctx, clauses.dependTypeAttrs), clauses.dependVars,
1954  clauses.allocateVars, clauses.allocatorVars);
1955 }
1956 
1957 LogicalResult TaskOp::verify() {
1958  LogicalResult verifyDependVars =
1959  verifyDependVarList(*this, getDepends(), getDependVars());
1960  return failed(verifyDependVars)
1961  ? verifyDependVars
1962  : verifyReductionVarList(*this, getInReductions(),
1963  getInReductionVars(),
1964  getInReductionVarsByref());
1965 }
1966 
1967 //===----------------------------------------------------------------------===//
1968 // TaskgroupOp
1969 //===----------------------------------------------------------------------===//
1970 
1971 void TaskgroupOp::build(OpBuilder &builder, OperationState &state,
1972  const TaskgroupClauseOps &clauses) {
1973  MLIRContext *ctx = builder.getContext();
1974  TaskgroupOp::build(
1975  builder, state, clauses.taskReductionVars,
1976  makeDenseBoolArrayAttr(ctx, clauses.taskReductionVarsByRef),
1977  makeArrayAttr(ctx, clauses.taskReductionDeclSymbols),
1978  clauses.allocateVars, clauses.allocatorVars);
1979 }
1980 
1981 LogicalResult TaskgroupOp::verify() {
1982  return verifyReductionVarList(*this, getTaskReductions(),
1983  getTaskReductionVars(),
1984  getTaskReductionVarsByref());
1985 }
1986 
1987 //===----------------------------------------------------------------------===//
1988 // TaskloopOp
1989 //===----------------------------------------------------------------------===//
1990 
1991 void TaskloopOp::build(OpBuilder &builder, OperationState &state,
1992  const TaskloopClauseOps &clauses) {
1993  MLIRContext *ctx = builder.getContext();
1994  // TODO Store clauses in op: privateVars, privatizers.
1995  TaskloopOp::build(
1996  builder, state, clauses.ifVar, clauses.finalVar, clauses.untiedAttr,
1997  clauses.mergeableAttr, clauses.inReductionVars,
1998  makeDenseBoolArrayAttr(ctx, clauses.inReductionVarsByRef),
1999  makeArrayAttr(ctx, clauses.inReductionDeclSymbols), clauses.reductionVars,
2000  makeDenseBoolArrayAttr(ctx, clauses.reductionVarsByRef),
2001  makeArrayAttr(ctx, clauses.reductionDeclSymbols), clauses.priorityVar,
2002  clauses.allocateVars, clauses.allocatorVars, clauses.grainsizeVar,
2003  clauses.numTasksVar, clauses.nogroupAttr);
2004 }
2005 
2006 SmallVector<Value> TaskloopOp::getAllReductionVars() {
2007  SmallVector<Value> allReductionNvars(getInReductionVars().begin(),
2008  getInReductionVars().end());
2009  allReductionNvars.insert(allReductionNvars.end(), getReductionVars().begin(),
2010  getReductionVars().end());
2011  return allReductionNvars;
2012 }
2013 
2014 LogicalResult TaskloopOp::verify() {
2015  if (getAllocateVars().size() != getAllocatorsVars().size())
2016  return emitError(
2017  "expected equal sizes for allocate and allocator variables");
2018  if (failed(verifyReductionVarList(*this, getReductions(), getReductionVars(),
2019  getReductionVarsByref())) ||
2020  failed(verifyReductionVarList(*this, getInReductions(),
2021  getInReductionVars(),
2022  getInReductionVarsByref())))
2023  return failure();
2024 
2025  if (!getReductionVars().empty() && getNogroup())
2026  return emitError("if a reduction clause is present on the taskloop "
2027  "directive, the nogroup clause must not be specified");
2028  for (auto var : getReductionVars()) {
2029  if (llvm::is_contained(getInReductionVars(), var))
2030  return emitError("the same list item cannot appear in both a reduction "
2031  "and an in_reduction clause");
2032  }
2033 
2034  if (getGrainSize() && getNumTasks()) {
2035  return emitError(
2036  "the grainsize clause and num_tasks clause are mutually exclusive and "
2037  "may not appear on the same taskloop directive");
2038  }
2039 
2040  if (!isWrapper())
2041  return emitOpError() << "must be a loop wrapper";
2042 
2043  if (LoopWrapperInterface nested = getNestedWrapper()) {
2044  // Check for the allowed leaf constructs that may appear in a composite
2045  // construct directly after TASKLOOP.
2046  if (!isa<SimdOp>(nested))
2047  return emitError() << "only supported nested wrapper is 'omp.simd'";
2048  }
2049  return success();
2050 }
2051 
2052 //===----------------------------------------------------------------------===//
2053 // LoopNestOp
2054 //===----------------------------------------------------------------------===//
2055 
2056 ParseResult LoopNestOp::parse(OpAsmParser &parser, OperationState &result) {
2057  // Parse an opening `(` followed by induction variables followed by `)`
2060  Type loopVarType;
2062  parser.parseColonType(loopVarType) ||
2063  // Parse loop bounds.
2064  parser.parseEqual() ||
2065  parser.parseOperandList(lbs, ivs.size(), OpAsmParser::Delimiter::Paren) ||
2066  parser.parseKeyword("to") ||
2067  parser.parseOperandList(ubs, ivs.size(), OpAsmParser::Delimiter::Paren))
2068  return failure();
2069 
2070  for (auto &iv : ivs)
2071  iv.type = loopVarType;
2072 
2073  // Parse "inclusive" flag.
2074  if (succeeded(parser.parseOptionalKeyword("inclusive")))
2075  result.addAttribute("inclusive",
2076  UnitAttr::get(parser.getBuilder().getContext()));
2077 
2078  // Parse step values.
2080  if (parser.parseKeyword("step") ||
2081  parser.parseOperandList(steps, ivs.size(), OpAsmParser::Delimiter::Paren))
2082  return failure();
2083 
2084  // Parse the body.
2085  Region *region = result.addRegion();
2086  if (parser.parseRegion(*region, ivs))
2087  return failure();
2088 
2089  // Resolve operands.
2090  if (parser.resolveOperands(lbs, loopVarType, result.operands) ||
2091  parser.resolveOperands(ubs, loopVarType, result.operands) ||
2092  parser.resolveOperands(steps, loopVarType, result.operands))
2093  return failure();
2094 
2095  // Parse the optional attribute list.
2096  return parser.parseOptionalAttrDict(result.attributes);
2097 }
2098 
2100  Region &region = getRegion();
2101  auto args = region.getArguments();
2102  p << " (" << args << ") : " << args[0].getType() << " = (" << getLowerBound()
2103  << ") to (" << getUpperBound() << ") ";
2104  if (getInclusive())
2105  p << "inclusive ";
2106  p << "step (" << getStep() << ") ";
2107  p.printRegion(region, /*printEntryBlockArgs=*/false);
2108 }
2109 
2110 void LoopNestOp::build(OpBuilder &builder, OperationState &state,
2111  const LoopNestClauseOps &clauses) {
2112  LoopNestOp::build(builder, state, clauses.loopLBVar, clauses.loopUBVar,
2113  clauses.loopStepVar, clauses.loopInclusiveAttr);
2114 }
2115 
2116 LogicalResult LoopNestOp::verify() {
2117  if (getLowerBound().empty())
2118  return emitOpError() << "must represent at least one loop";
2119 
2120  if (getLowerBound().size() != getIVs().size())
2121  return emitOpError() << "number of range arguments and IVs do not match";
2122 
2123  for (auto [lb, iv] : llvm::zip_equal(getLowerBound(), getIVs())) {
2124  if (lb.getType() != iv.getType())
2125  return emitOpError()
2126  << "range argument type does not match corresponding IV type";
2127  }
2128 
2129  auto wrapper =
2130  llvm::dyn_cast_if_present<LoopWrapperInterface>((*this)->getParentOp());
2131 
2132  if (!wrapper || !wrapper.isWrapper())
2133  return emitOpError() << "expects parent op to be a valid loop wrapper";
2134 
2135  return success();
2136 }
2137 
2138 void LoopNestOp::gatherWrappers(
2140  Operation *parent = (*this)->getParentOp();
2141  while (auto wrapper =
2142  llvm::dyn_cast_if_present<LoopWrapperInterface>(parent)) {
2143  if (!wrapper.isWrapper())
2144  break;
2145  wrappers.push_back(wrapper);
2146  parent = parent->getParentOp();
2147  }
2148 }
2149 
2150 //===----------------------------------------------------------------------===//
2151 // Critical construct (2.17.1)
2152 //===----------------------------------------------------------------------===//
2153 
2154 void CriticalDeclareOp::build(OpBuilder &builder, OperationState &state,
2155  const CriticalClauseOps &clauses) {
2156  CriticalDeclareOp::build(builder, state, clauses.criticalNameAttr,
2157  clauses.hintAttr);
2158 }
2159 
2160 LogicalResult CriticalDeclareOp::verify() {
2161  return verifySynchronizationHint(*this, getHintVal());
2162 }
2163 
2164 LogicalResult CriticalOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2165  if (getNameAttr()) {
2166  SymbolRefAttr symbolRef = getNameAttr();
2167  auto decl = symbolTable.lookupNearestSymbolFrom<CriticalDeclareOp>(
2168  *this, symbolRef);
2169  if (!decl) {
2170  return emitOpError() << "expected symbol reference " << symbolRef
2171  << " to point to a critical declaration";
2172  }
2173  }
2174 
2175  return success();
2176 }
2177 
2178 //===----------------------------------------------------------------------===//
2179 // Ordered construct
2180 //===----------------------------------------------------------------------===//
2181 
2182 static LogicalResult verifyOrderedParent(Operation &op) {
2183  bool hasRegion = op.getNumRegions() > 0;
2184  auto loopOp = op.getParentOfType<LoopNestOp>();
2185  if (!loopOp) {
2186  if (hasRegion)
2187  return success();
2188 
2189  // TODO: Consider if this needs to be the case only for the standalone
2190  // variant of the ordered construct.
2191  return op.emitOpError() << "must be nested inside of a loop";
2192  }
2193 
2194  Operation *wrapper = loopOp->getParentOp();
2195  if (auto wsloopOp = dyn_cast<WsloopOp>(wrapper)) {
2196  IntegerAttr orderedAttr = wsloopOp.getOrderedValAttr();
2197  if (!orderedAttr)
2198  return op.emitOpError() << "the enclosing worksharing-loop region must "
2199  "have an ordered clause";
2200 
2201  if (hasRegion && orderedAttr.getInt() != 0)
2202  return op.emitOpError() << "the enclosing loop's ordered clause must not "
2203  "have a parameter present";
2204 
2205  if (!hasRegion && orderedAttr.getInt() == 0)
2206  return op.emitOpError() << "the enclosing loop's ordered clause must "
2207  "have a parameter present";
2208  } else if (!isa<SimdOp>(wrapper)) {
2209  return op.emitOpError() << "must be nested inside of a worksharing, simd "
2210  "or worksharing simd loop";
2211  }
2212  return success();
2213 }
2214 
2215 void OrderedOp::build(OpBuilder &builder, OperationState &state,
2216  const OrderedOpClauseOps &clauses) {
2217  OrderedOp::build(builder, state, clauses.doacrossDependTypeAttr,
2218  clauses.doacrossNumLoopsAttr, clauses.doacrossVectorVars);
2219 }
2220 
2221 LogicalResult OrderedOp::verify() {
2222  if (failed(verifyOrderedParent(**this)))
2223  return failure();
2224 
2225  auto wrapper = (*this)->getParentOfType<WsloopOp>();
2226  if (!wrapper || *wrapper.getOrderedVal() != *getNumLoopsVal())
2227  return emitOpError() << "number of variables in depend clause does not "
2228  << "match number of iteration variables in the "
2229  << "doacross loop";
2230 
2231  return success();
2232 }
2233 
2234 void OrderedRegionOp::build(OpBuilder &builder, OperationState &state,
2235  const OrderedRegionClauseOps &clauses) {
2236  OrderedRegionOp::build(builder, state, clauses.parLevelSimdAttr);
2237 }
2238 
2239 LogicalResult OrderedRegionOp::verify() {
2240  // TODO: The code generation for ordered simd directive is not supported yet.
2241  if (getSimd())
2242  return failure();
2243 
2244  return verifyOrderedParent(**this);
2245 }
2246 
2247 //===----------------------------------------------------------------------===//
2248 // TaskwaitOp
2249 //===----------------------------------------------------------------------===//
2250 
2251 void TaskwaitOp::build(OpBuilder &builder, OperationState &state,
2252  const TaskwaitClauseOps &clauses) {
2253  // TODO Store clauses in op: dependTypeAttrs, dependVars, nowaitAttr.
2254  TaskwaitOp::build(builder, state);
2255 }
2256 
2257 //===----------------------------------------------------------------------===//
2258 // Verifier for AtomicReadOp
2259 //===----------------------------------------------------------------------===//
2260 
2261 LogicalResult AtomicReadOp::verify() {
2262  if (verifyCommon().failed())
2263  return mlir::failure();
2264 
2265  if (auto mo = getMemoryOrderVal()) {
2266  if (*mo == ClauseMemoryOrderKind::Acq_rel ||
2267  *mo == ClauseMemoryOrderKind::Release) {
2268  return emitError(
2269  "memory-order must not be acq_rel or release for atomic reads");
2270  }
2271  }
2272  return verifySynchronizationHint(*this, getHintVal());
2273 }
2274 
2275 //===----------------------------------------------------------------------===//
2276 // Verifier for AtomicWriteOp
2277 //===----------------------------------------------------------------------===//
2278 
2279 LogicalResult AtomicWriteOp::verify() {
2280  if (verifyCommon().failed())
2281  return mlir::failure();
2282 
2283  if (auto mo = getMemoryOrderVal()) {
2284  if (*mo == ClauseMemoryOrderKind::Acq_rel ||
2285  *mo == ClauseMemoryOrderKind::Acquire) {
2286  return emitError(
2287  "memory-order must not be acq_rel or acquire for atomic writes");
2288  }
2289  }
2290  return verifySynchronizationHint(*this, getHintVal());
2291 }
2292 
2293 //===----------------------------------------------------------------------===//
2294 // Verifier for AtomicUpdateOp
2295 //===----------------------------------------------------------------------===//
2296 
2297 LogicalResult AtomicUpdateOp::canonicalize(AtomicUpdateOp op,
2298  PatternRewriter &rewriter) {
2299  if (op.isNoOp()) {
2300  rewriter.eraseOp(op);
2301  return success();
2302  }
2303  if (Value writeVal = op.getWriteOpVal()) {
2304  rewriter.replaceOpWithNewOp<AtomicWriteOp>(op, op.getX(), writeVal,
2305  op.getHintValAttr(),
2306  op.getMemoryOrderValAttr());
2307  return success();
2308  }
2309  return failure();
2310 }
2311 
2312 LogicalResult AtomicUpdateOp::verify() {
2313  if (verifyCommon().failed())
2314  return mlir::failure();
2315 
2316  if (auto mo = getMemoryOrderVal()) {
2317  if (*mo == ClauseMemoryOrderKind::Acq_rel ||
2318  *mo == ClauseMemoryOrderKind::Acquire) {
2319  return emitError(
2320  "memory-order must not be acq_rel or acquire for atomic updates");
2321  }
2322  }
2323 
2324  return verifySynchronizationHint(*this, getHintVal());
2325 }
2326 
2327 LogicalResult AtomicUpdateOp::verifyRegions() { return verifyRegionsCommon(); }
2328 
2329 //===----------------------------------------------------------------------===//
2330 // Verifier for AtomicCaptureOp
2331 //===----------------------------------------------------------------------===//
2332 
2333 AtomicReadOp AtomicCaptureOp::getAtomicReadOp() {
2334  if (auto op = dyn_cast<AtomicReadOp>(getFirstOp()))
2335  return op;
2336  return dyn_cast<AtomicReadOp>(getSecondOp());
2337 }
2338 
2339 AtomicWriteOp AtomicCaptureOp::getAtomicWriteOp() {
2340  if (auto op = dyn_cast<AtomicWriteOp>(getFirstOp()))
2341  return op;
2342  return dyn_cast<AtomicWriteOp>(getSecondOp());
2343 }
2344 
2345 AtomicUpdateOp AtomicCaptureOp::getAtomicUpdateOp() {
2346  if (auto op = dyn_cast<AtomicUpdateOp>(getFirstOp()))
2347  return op;
2348  return dyn_cast<AtomicUpdateOp>(getSecondOp());
2349 }
2350 
2351 LogicalResult AtomicCaptureOp::verify() {
2352  return verifySynchronizationHint(*this, getHintVal());
2353 }
2354 
2355 LogicalResult AtomicCaptureOp::verifyRegions() {
2356  if (verifyRegionsCommon().failed())
2357  return mlir::failure();
2358 
2359  if (getFirstOp()->getAttr("hint_val") || getSecondOp()->getAttr("hint_val"))
2360  return emitOpError(
2361  "operations inside capture region must not have hint clause");
2362 
2363  if (getFirstOp()->getAttr("memory_order_val") ||
2364  getSecondOp()->getAttr("memory_order_val"))
2365  return emitOpError(
2366  "operations inside capture region must not have memory_order clause");
2367  return success();
2368 }
2369 
2370 //===----------------------------------------------------------------------===//
2371 // CancelOp
2372 //===----------------------------------------------------------------------===//
2373 
2374 void CancelOp::build(OpBuilder &builder, OperationState &state,
2375  const CancelClauseOps &clauses) {
2376  CancelOp::build(builder, state, clauses.cancelDirectiveNameAttr,
2377  clauses.ifVar);
2378 }
2379 
2380 LogicalResult CancelOp::verify() {
2381  ClauseCancellationConstructType cct = getCancellationConstructTypeVal();
2382  Operation *parentOp = (*this)->getParentOp();
2383 
2384  if (!parentOp) {
2385  return emitOpError() << "must be used within a region supporting "
2386  "cancel directive";
2387  }
2388 
2389  if ((cct == ClauseCancellationConstructType::Parallel) &&
2390  !isa<ParallelOp>(parentOp)) {
2391  return emitOpError() << "cancel parallel must appear "
2392  << "inside a parallel region";
2393  }
2394  if (cct == ClauseCancellationConstructType::Loop) {
2395  auto loopOp = dyn_cast<LoopNestOp>(parentOp);
2396  auto wsloopOp = llvm::dyn_cast_if_present<WsloopOp>(
2397  loopOp ? loopOp->getParentOp() : nullptr);
2398 
2399  if (!wsloopOp) {
2400  return emitOpError()
2401  << "cancel loop must appear inside a worksharing-loop region";
2402  }
2403  if (wsloopOp.getNowaitAttr()) {
2404  return emitError() << "A worksharing construct that is canceled "
2405  << "must not have a nowait clause";
2406  }
2407  if (wsloopOp.getOrderedValAttr()) {
2408  return emitError() << "A worksharing construct that is canceled "
2409  << "must not have an ordered clause";
2410  }
2411 
2412  } else if (cct == ClauseCancellationConstructType::Sections) {
2413  if (!(isa<SectionsOp>(parentOp) || isa<SectionOp>(parentOp))) {
2414  return emitOpError() << "cancel sections must appear "
2415  << "inside a sections region";
2416  }
2417  if (isa_and_nonnull<SectionsOp>(parentOp->getParentOp()) &&
2418  cast<SectionsOp>(parentOp->getParentOp()).getNowaitAttr()) {
2419  return emitError() << "A sections construct that is canceled "
2420  << "must not have a nowait clause";
2421  }
2422  }
2423  // TODO : Add more when we support taskgroup.
2424  return success();
2425 }
2426 
2427 //===----------------------------------------------------------------------===//
2428 // CancellationPointOp
2429 //===----------------------------------------------------------------------===//
2430 
2431 void CancellationPointOp::build(OpBuilder &builder, OperationState &state,
2432  const CancellationPointClauseOps &clauses) {
2433  CancellationPointOp::build(builder, state, clauses.cancelDirectiveNameAttr);
2434 }
2435 
2436 LogicalResult CancellationPointOp::verify() {
2437  ClauseCancellationConstructType cct = getCancellationConstructTypeVal();
2438  Operation *parentOp = (*this)->getParentOp();
2439 
2440  if (!parentOp) {
2441  return emitOpError() << "must be used within a region supporting "
2442  "cancellation point directive";
2443  }
2444 
2445  if ((cct == ClauseCancellationConstructType::Parallel) &&
2446  !(isa<ParallelOp>(parentOp))) {
2447  return emitOpError() << "cancellation point parallel must appear "
2448  << "inside a parallel region";
2449  }
2450  if ((cct == ClauseCancellationConstructType::Loop) &&
2451  (!isa<LoopNestOp>(parentOp) || !isa<WsloopOp>(parentOp->getParentOp()))) {
2452  return emitOpError() << "cancellation point loop must appear "
2453  << "inside a worksharing-loop region";
2454  }
2455  if ((cct == ClauseCancellationConstructType::Sections) &&
2456  !(isa<SectionsOp>(parentOp) || isa<SectionOp>(parentOp))) {
2457  return emitOpError() << "cancellation point sections must appear "
2458  << "inside a sections region";
2459  }
2460  // TODO : Add more when we support taskgroup.
2461  return success();
2462 }
2463 
2464 //===----------------------------------------------------------------------===//
2465 // MapBoundsOp
2466 //===----------------------------------------------------------------------===//
2467 
2468 LogicalResult MapBoundsOp::verify() {
2469  auto extent = getExtent();
2470  auto upperbound = getUpperBound();
2471  if (!extent && !upperbound)
2472  return emitError("expected extent or upperbound.");
2473  return success();
2474 }
2475 
2476 void PrivateClauseOp::build(OpBuilder &odsBuilder, OperationState &odsState,
2477  TypeRange /*result_types*/, StringAttr symName,
2478  TypeAttr type) {
2479  PrivateClauseOp::build(
2480  odsBuilder, odsState, symName, type,
2482  DataSharingClauseType::Private));
2483 }
2484 
2485 LogicalResult PrivateClauseOp::verify() {
2486  Type symType = getType();
2487 
2488  auto verifyTerminator = [&](Operation *terminator,
2489  bool yieldsValue) -> LogicalResult {
2490  if (!terminator->getBlock()->getSuccessors().empty())
2491  return success();
2492 
2493  if (!llvm::isa<YieldOp>(terminator))
2494  return mlir::emitError(terminator->getLoc())
2495  << "expected exit block terminator to be an `omp.yield` op.";
2496 
2497  YieldOp yieldOp = llvm::cast<YieldOp>(terminator);
2498  TypeRange yieldedTypes = yieldOp.getResults().getTypes();
2499 
2500  if (!yieldsValue) {
2501  if (yieldedTypes.empty())
2502  return success();
2503 
2504  return mlir::emitError(terminator->getLoc())
2505  << "Did not expect any values to be yielded.";
2506  }
2507 
2508  if (yieldedTypes.size() == 1 && yieldedTypes.front() == symType)
2509  return success();
2510 
2511  auto error = mlir::emitError(yieldOp.getLoc())
2512  << "Invalid yielded value. Expected type: " << symType
2513  << ", got: ";
2514 
2515  if (yieldedTypes.empty())
2516  error << "None";
2517  else
2518  error << yieldedTypes;
2519 
2520  return error;
2521  };
2522 
2523  auto verifyRegion = [&](Region &region, unsigned expectedNumArgs,
2524  StringRef regionName,
2525  bool yieldsValue) -> LogicalResult {
2526  assert(!region.empty());
2527 
2528  if (region.getNumArguments() != expectedNumArgs)
2529  return mlir::emitError(region.getLoc())
2530  << "`" << regionName << "`: "
2531  << "expected " << expectedNumArgs
2532  << " region arguments, got: " << region.getNumArguments();
2533 
2534  for (Block &block : region) {
2535  // MLIR will verify the absence of the terminator for us.
2536  if (!block.mightHaveTerminator())
2537  continue;
2538 
2539  if (failed(verifyTerminator(block.getTerminator(), yieldsValue)))
2540  return failure();
2541  }
2542 
2543  return success();
2544  };
2545 
2546  if (failed(verifyRegion(getAllocRegion(), /*expectedNumArgs=*/1, "alloc",
2547  /*yieldsValue=*/true)))
2548  return failure();
2549 
2550  DataSharingClauseType dsType = getDataSharingType();
2551 
2552  if (dsType == DataSharingClauseType::Private && !getCopyRegion().empty())
2553  return emitError("`private` clauses require only an `alloc` region.");
2554 
2555  if (dsType == DataSharingClauseType::FirstPrivate && getCopyRegion().empty())
2556  return emitError(
2557  "`firstprivate` clauses require both `alloc` and `copy` regions.");
2558 
2559  if (dsType == DataSharingClauseType::FirstPrivate &&
2560  failed(verifyRegion(getCopyRegion(), /*expectedNumArgs=*/2, "copy",
2561  /*yieldsValue=*/true)))
2562  return failure();
2563 
2564  if (!getDeallocRegion().empty() &&
2565  failed(verifyRegion(getDeallocRegion(), /*expectedNumArgs=*/1, "dealloc",
2566  /*yieldsValue=*/false)))
2567  return failure();
2568 
2569  return success();
2570 }
2571 
2572 //===----------------------------------------------------------------------===//
2573 // Spec 5.2: Masked construct (10.5)
2574 //===----------------------------------------------------------------------===//
2575 
2576 void MaskedOp::build(OpBuilder &builder, OperationState &state,
2577  const MaskedClauseOps &clauses) {
2578  MaskedOp::build(builder, state, clauses.filteredThreadIdVar);
2579 }
2580 
2581 #define GET_ATTRDEF_CLASSES
2582 #include "mlir/Dialect/OpenMP/OpenMPOpsAttributes.cpp.inc"
2583 
2584 #define GET_OP_CLASSES
2585 #include "mlir/Dialect/OpenMP/OpenMPOps.cpp.inc"
2586 
2587 #define GET_TYPEDEF_CLASSES
2588 #include "mlir/Dialect/OpenMP/OpenMPOpsTypes.cpp.inc"
static std::optional< int64_t > getUpperBound(Value iv)
Gets the constant upper bound on an affine.for iv.
Definition: AffineOps.cpp:720
static std::optional< int64_t > getLowerBound(Value iv)
Gets the constant lower bound on an iv.
Definition: AffineOps.cpp:712
static void visit(Operation *op, DenseSet< Operation * > &visited)
Visits all the pdl.operand(s), pdl.result(s), and pdl.operation(s) connected to the given operation.
Definition: PDL.cpp:63
static MLIRContext * getContext(OpFoldResult val)
void printClauseAttr(OpAsmPrinter &p, Operation *op, ClauseAttr attr)
static void printPrivateList(OpAsmPrinter &p, Operation *op, ValueRange privateVarOperands, TypeRange privateVarTypes, ArrayAttr privatizerSymbols)
static ParseResult parseAlignedClause(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &alignedItems, SmallVectorImpl< Type > &types, ArrayAttr &alignmentValues)
aligned ::= aligned ( aligned-list ) aligned-list := aligned-val | aligned-val aligned-list aligned-v...
static ArrayAttr makeArrayAttr(MLIRContext *context, llvm::ArrayRef< Attribute > attrs)
static ParseResult parseClauseAttr(AsmParser &parser, ClauseAttr &attr)
static void printDependVarList(OpAsmPrinter &p, Operation *op, OperandRange dependVars, TypeRange dependTypes, std::optional< ArrayAttr > depends)
Print Depend clause.
static ParseResult parseCaptureType(OpAsmParser &parser, VariableCaptureKindAttr &mapCapture)
static DenseBoolArrayAttr makeDenseBoolArrayAttr(MLIRContext *ctx, const ArrayRef< bool > boolArray)
static ParseResult parseLinearClause(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &vars, SmallVectorImpl< Type > &types, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &stepVars)
linear ::= linear ( linear-list ) linear-list := linear-val | linear-val linear-list linear-val := ss...
static void printAllocateAndAllocator(OpAsmPrinter &p, Operation *op, OperandRange varsAllocate, TypeRange typesAllocate, OperandRange varsAllocator, TypeRange typesAllocator)
Print allocate clause.
static LogicalResult verifyAlignedClause(Operation *op, std::optional< ArrayAttr > alignmentValues, OperandRange alignedVariables)
static ParseResult parseParallelRegion(OpAsmParser &parser, Region &region, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &reductionVarOperands, SmallVectorImpl< Type > &reductionVarTypes, DenseBoolArrayAttr &reductionByRef, ArrayAttr &reductionSymbols, llvm::SmallVectorImpl< OpAsmParser::UnresolvedOperand > &privateVarOperands, llvm::SmallVectorImpl< Type > &privateVarsTypes, ArrayAttr &privatizerSymbols)
static ParseResult parseAllocateAndAllocator(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &operandsAllocate, SmallVectorImpl< Type > &typesAllocate, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &operandsAllocator, SmallVectorImpl< Type > &typesAllocator)
Parse an allocate clause with allocators and a list of operands with types.
static ParseResult parseSynchronizationHint(OpAsmParser &parser, IntegerAttr &hintAttr)
Parses a Synchronization Hint clause.
uint64_t mapTypeToBitFlag(uint64_t value, llvm::omp::OpenMPOffloadMappingFlags flag)
static void printAlignedClause(OpAsmPrinter &p, Operation *op, ValueRange alignedVars, TypeRange alignedVarTypes, std::optional< ArrayAttr > alignmentValues)
Print Aligned Clause.
static LogicalResult verifyMapClause(Operation *op, OperandRange mapOperands)
void printWsloop(OpAsmPrinter &p, Operation *op, Region &region, ValueRange reductionOperands, TypeRange reductionTypes, DenseBoolArrayAttr isByRef, ArrayAttr reductionSymbols)
static LogicalResult verifyDependVarList(Operation *op, std::optional< ArrayAttr > depends, OperandRange dependVars)
Verifies Depend clause.
static LogicalResult verifySynchronizationHint(Operation *op, uint64_t hint)
Verifies a synchronization hint clause.
static LogicalResult verifyReductionVarList(Operation *op, std::optional< ArrayAttr > reductions, OperandRange reductionVars, std::optional< ArrayRef< bool >> byRef)
Verifies Reduction Clause.
static void printOrderClause(OpAsmPrinter &p, Operation *op, ClauseOrderKindAttr kindAttr, OrderModifierAttr modifierAttr)
static ParseResult parseReductionVarList(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &operands, SmallVectorImpl< Type > &types, DenseBoolArrayAttr &isByRef, ArrayAttr &reductionSymbols)
reduction-entry-list ::= reduction-entry | reduction-entry-list , reduction-entry reduction-entry ::=...
static void printSynchronizationHint(OpAsmPrinter &p, Operation *op, IntegerAttr hintAttr)
Prints a Synchronization Hint clause.
static ParseResult parseClauseWithRegionArgs(OpAsmParser &parser, Region &region, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &operands, SmallVectorImpl< Type > &types, DenseBoolArrayAttr &isByRef, ArrayAttr &symbols, SmallVectorImpl< OpAsmParser::Argument > &regionPrivateArgs)
static void printParallelRegion(OpAsmPrinter &p, Operation *op, Region &region, ValueRange reductionVarOperands, TypeRange reductionVarTypes, DenseBoolArrayAttr reductionVarIsByRef, ArrayAttr reductionSymbols, ValueRange privateVarOperands, TypeRange privateVarTypes, ArrayAttr privatizerSymbols)
static void printAtomicReductionRegion(OpAsmPrinter &printer, DeclareReductionOp op, Region &region)
ParseResult parseWsloop(OpAsmParser &parser, Region &region, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &reductionOperands, SmallVectorImpl< Type > &reductionTypes, DenseBoolArrayAttr &reductionByRef, ArrayAttr &reductionSymbols)
static ParseResult parseCopyPrivateVarList(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &operands, SmallVectorImpl< Type > &types, ArrayAttr &copyPrivateSymbols)
copyprivate-entry-list ::= copyprivate-entry | copyprivate-entry-list , copyprivate-entry copyprivate...
static void printCopyPrivateVarList(OpAsmPrinter &p, Operation *op, OperandRange copyPrivateVars, TypeRange copyPrivateTypes, std::optional< ArrayAttr > copyPrivateFuncs)
Print CopyPrivate clause.
static void printLinearClause(OpAsmPrinter &p, Operation *op, ValueRange linearVars, TypeRange linearVarTypes, ValueRange linearStepVars)
Print Linear Clause.
static void printClauseWithRegionArgs(OpAsmPrinter &p, Operation *op, ValueRange argsSubrange, StringRef clauseName, ValueRange operands, TypeRange types, DenseBoolArrayAttr byRef, ArrayAttr symbols)
static ParseResult parseMapClause(OpAsmParser &parser, IntegerAttr &mapType)
Parses a map_entries map type from a string format back into its numeric value.
static LogicalResult verifyOrderedParent(Operation &op)
static void printMembersIndex(OpAsmPrinter &p, MapInfoOp op, DenseIntElementsAttr membersIdx)
static ParseResult parseScheduleClause(OpAsmParser &parser, ClauseScheduleKindAttr &scheduleAttr, ScheduleModifierAttr &scheduleModifier, UnitAttr &simdModifier, std::optional< OpAsmParser::UnresolvedOperand > &chunkSize, Type &chunkType)
schedule ::= schedule ( sched-list ) sched-list ::= sched-val | sched-val sched-list | sched-val ,...
static LogicalResult verifyNontemporalClause(Operation *op, OperandRange nontemporalVariables)
static ParseResult verifyScheduleModifiers(OpAsmParser &parser, SmallVectorImpl< SmallString< 12 >> &modifiers)
static void printReductionVarList(OpAsmPrinter &p, Operation *op, OperandRange reductionVars, TypeRange reductionTypes, std::optional< DenseBoolArrayAttr > isByRef, std::optional< ArrayAttr > reductions)
Print Reduction clause.
static void printScheduleClause(OpAsmPrinter &p, Operation *op, ClauseScheduleKindAttr schedAttr, ScheduleModifierAttr modifier, UnitAttr simd, Value scheduleChunkVar, Type scheduleChunkType)
Print schedule clause.
static ParseResult parseCleanupReductionRegion(OpAsmParser &parser, Region &region)
static ParseResult parseAtomicReductionRegion(OpAsmParser &parser, Region &region)
static void printCaptureType(OpAsmPrinter &p, Operation *op, VariableCaptureKindAttr mapCaptureType)
static ParseResult parsePrivateList(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &privateOperands, SmallVectorImpl< Type > &privateOperandTypes, ArrayAttr &privatizerSymbols)
static bool opInGlobalImplicitParallelRegion(Operation *op)
static LogicalResult verifyCopyPrivateVarList(Operation *op, OperandRange copyPrivateVars, std::optional< ArrayAttr > copyPrivateFuncs)
Verifies CopyPrivate Clause.
static LogicalResult verifyPrivateVarList(OpType &op)
static ParseResult parseDependVarList(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &operands, SmallVectorImpl< Type > &types, ArrayAttr &dependsArray)
depend-entry-list ::= depend-entry | depend-entry-list , depend-entry depend-entry ::= depend-kind ->...
static ParseResult parseOrderClause(OpAsmParser &parser, ClauseOrderKindAttr &kindAttr, OrderModifierAttr &modifierAttr)
static void printMapClause(OpAsmPrinter &p, Operation *op, IntegerAttr mapType)
Prints a map_entries map type from its numeric value out into its string format.
static ParseResult parseMapEntries(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &mapOperands, SmallVectorImpl< Type > &mapOperandTypes)
static void printMapEntries(OpAsmPrinter &p, Operation *op, OperandRange mapOperands, TypeRange mapOperandTypes)
static void printCleanupReductionRegion(OpAsmPrinter &printer, DeclareReductionOp op, Region &region)
static ParseResult parseMembersIndex(OpAsmParser &parser, DenseIntElementsAttr &membersIdx)
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
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:215
This base class exposes generic asm parser hooks, usable across the various derived parsers.
@ Paren
Parens surrounding zero or more operands.
virtual ParseResult parseCommaSeparatedList(Delimiter delimiter, function_ref< ParseResult()> parseElementFn, StringRef contextMessage=StringRef())=0
Parse a list of comma-separated items with an optional delimiter.
virtual Builder & getBuilder() const =0
Return a builder which provides useful access to MLIRContext, global objects like types and attribute...
virtual ParseResult parseOptionalAttrDict(NamedAttrList &result)=0
Parse a named dictionary into 'result' if it is present.
virtual ParseResult parseOptionalEqual()=0
Parse a = token if present.
virtual ParseResult parseOptionalKeyword(StringRef keyword)=0
Parse the given keyword if present.
MLIRContext * getContext() const
Definition: AsmPrinter.cpp:73
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
virtual ParseResult parseOptionalColon()=0
Parse a : token if present.
virtual ParseResult parseLSquare()=0
Parse a [ token.
virtual ParseResult parseRSquare()=0
Parse a ] token.
ParseResult parseInteger(IntT &result)
Parse an integer value from the stream.
virtual ParseResult parseOptionalArrow()=0
Parse a '->' token if present.
virtual ParseResult parseEqual()=0
Parse a = token.
virtual ParseResult parseColonType(Type &result)=0
Parse a colon followed by a type.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
virtual ParseResult parseOptionalComma()=0
Parse a , token if present.
virtual ParseResult parseColon()=0
Parse a : token.
virtual SMLoc getNameLoc() const =0
Return the location of the original name token.
virtual ParseResult parseArrow()=0
Parse a '->' token.
virtual ParseResult parseType(Type &result)=0
Parse a type.
ParseResult parseKeyword(StringRef keyword)
Parse a given keyword.
Block represents an ordered list of Operations.
Definition: Block.h:31
ValueTypeRange< BlockArgListType > getArgumentTypes()
Return a range containing the types of the arguments for this block.
Definition: Block.cpp:148
BlockArgument getArgument(unsigned i)
Definition: Block.h:127
unsigned getNumArguments()
Definition: Block.h:126
SuccessorRange getSuccessors()
Definition: Block.h:265
BlockArgListType getArguments()
Definition: Block.h:85
Operation & front()
Definition: Block.h:151
IntegerAttr getIntegerAttr(Type type, int64_t value)
Definition: Builders.cpp:242
IntegerType getI64Type()
Definition: Builders.cpp:89
IntegerType getIntegerType(unsigned width)
Definition: Builders.cpp:91
MLIRContext * getContext() const
Definition: Builders.h:55
An attribute that represents a reference to a dense integer vector or tensor object.
static DenseIntElementsAttr get(const ShapedType &type, Arg &&arg)
Get an instance of a DenseIntElementsAttr with the given arguments.
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:60
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
virtual ParseResult parseRegion(Region &region, ArrayRef< Argument > arguments={}, bool enableNameShadowing=false)=0
Parses a region.
virtual ParseResult parseArgumentList(SmallVectorImpl< Argument > &result, Delimiter delimiter=Delimiter::None, bool allowType=false, bool allowAttrs=false)=0
Parse zero or more arguments with a specified surrounding delimiter.
ParseResult resolveOperands(Operands &&operands, Type type, SmallVectorImpl< Value > &result)
Resolve a list of operands to SSA values, emitting an error on failure, or appending the results to t...
virtual ParseResult parseOperand(UnresolvedOperand &result, bool allowResultNumber=true)=0
Parse a single SSA value operand name along with a result number if allowResultNumber is true.
virtual ParseResult parseOperandList(SmallVectorImpl< UnresolvedOperand > &result, Delimiter delimiter=Delimiter::None, bool allowResultNumber=true, int requiredOperandCount=-1)=0
Parse zero or more SSA comma-separated operand references with a specified surrounding delimiter,...
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
virtual void printRegion(Region &blocks, bool printEntryBlockArgs=true, bool printBlockTerminators=true, bool printEmptyBlock=false)=0
Prints a region.
This class helps build Operations.
Definition: Builders.h:210
This class implements the operand iterators for the Operation class.
Definition: ValueRange.h:42
type_range getType() const
Definition: ValueRange.cpp:30
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
Dialect * getDialect()
Return the dialect this operation is associated with, or nullptr if the associated dialect is not loa...
Definition: Operation.h:220
MLIRContext * getContext()
Return the context this operation is associated with.
Definition: Operation.h:216
unsigned getNumRegions()
Returns the number of regions held by this operation.
Definition: Operation.h:669
Location getLoc()
The source location the operation was defined or derived from.
Definition: Operation.h:223
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Definition: Operation.h:234
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
Definition: Operation.cpp:268
Block * getBlock()
Returns the operation block that contains this operation.
Definition: Operation.h:213
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
Definition: Operation.h:238
Region & getRegion(unsigned index)
Returns the region held by this operation at position 'index'.
Definition: Operation.h:682
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
Definition: Operation.cpp:671
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
Definition: PatternMatch.h:785
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition: Region.h:26
BlockArgListType getArguments()
Definition: Region.h:81
bool empty()
Definition: Region.h:60
unsigned getNumArguments()
Definition: Region.h:123
Location getLoc()
Return a location for this region.
Definition: Region.cpp:31
Block & front()
Definition: Region.h:65
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
Definition: PatternMatch.h:536
This class represents a collection of SymbolTables.
Definition: SymbolTable.h:283
Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of,...
This class provides an abstraction over the various different ranges of value types.
Definition: TypeRange.h:36
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
This class provides an abstraction over the different types of ranges over Values.
Definition: ValueRange.h:381
type_range getType() const
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
Type getType() const
Return the type of this value.
Definition: Value.h:129
Base class for DenseArrayAttr that is instantiated and specialized for each supported element type be...
static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef< T > content)
Builder from ArrayRef<T>.
Runtime
Potential runtimes for AMD GPU kernels.
Definition: Runtimes.h:15
QueryRef parse(llvm::StringRef line, const QuerySession &qs)
Definition: Query.cpp:20
Include the generated interface declarations.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
Definition: Utils.cpp:305
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
Definition: Verifier.cpp:421
This is the representation of an operand reference.
This represents an operation in an abstracted form, suitable for use with the builder APIs.
SmallVector< Value, 4 > operands
void addAttribute(StringRef name, Attribute attr)
Add an attribute with the specified name.
NamedAttrList attributes
Region * addRegion()
Create a region that should be attached to the operation.
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.