MLIR  16.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 
15 #include "mlir/IR/Attributes.h"
19 
20 #include "llvm/ADT/BitVector.h"
21 #include "llvm/ADT/SmallString.h"
22 #include "llvm/ADT/StringExtras.h"
23 #include "llvm/ADT/StringRef.h"
24 #include "llvm/ADT/TypeSwitch.h"
25 #include <cstddef>
26 
27 #include "mlir/Dialect/OpenMP/OpenMPOpsDialect.cpp.inc"
28 #include "mlir/Dialect/OpenMP/OpenMPOpsEnums.cpp.inc"
29 #include "mlir/Dialect/OpenMP/OpenMPOpsInterfaces.cpp.inc"
30 #include "mlir/Dialect/OpenMP/OpenMPTypeInterfaces.cpp.inc"
31 
32 using namespace mlir;
33 using namespace mlir::omp;
34 
35 namespace {
36 /// Model for pointer-like types that already provide a `getElementType` method.
37 template <typename T>
38 struct PointerLikeModel
39  : public PointerLikeType::ExternalModel<PointerLikeModel<T>, T> {
40  Type getElementType(Type pointer) const {
41  return pointer.cast<T>().getElementType();
42  }
43 };
44 } // namespace
45 
46 void OpenMPDialect::initialize() {
47  addOperations<
48 #define GET_OP_LIST
49 #include "mlir/Dialect/OpenMP/OpenMPOps.cpp.inc"
50  >();
51  addAttributes<
52 #define GET_ATTRDEF_LIST
53 #include "mlir/Dialect/OpenMP/OpenMPOpsAttributes.cpp.inc"
54  >();
55 
56  LLVM::LLVMPointerType::attachInterface<
57  PointerLikeModel<LLVM::LLVMPointerType>>(*getContext());
58  MemRefType::attachInterface<PointerLikeModel<MemRefType>>(*getContext());
59 }
60 
61 //===----------------------------------------------------------------------===//
62 // Parser and printer for Allocate Clause
63 //===----------------------------------------------------------------------===//
64 
65 /// Parse an allocate clause with allocators and a list of operands with types.
66 ///
67 /// allocate-operand-list :: = allocate-operand |
68 /// allocator-operand `,` allocate-operand-list
69 /// allocate-operand :: = ssa-id-and-type -> ssa-id-and-type
70 /// ssa-id-and-type ::= ssa-id `:` type
72  OpAsmParser &parser,
74  SmallVectorImpl<Type> &typesAllocate,
76  SmallVectorImpl<Type> &typesAllocator) {
77 
78  return parser.parseCommaSeparatedList([&]() {
80  Type type;
81  if (parser.parseOperand(operand) || parser.parseColonType(type))
82  return failure();
83  operandsAllocator.push_back(operand);
84  typesAllocator.push_back(type);
85  if (parser.parseArrow())
86  return failure();
87  if (parser.parseOperand(operand) || parser.parseColonType(type))
88  return failure();
89 
90  operandsAllocate.push_back(operand);
91  typesAllocate.push_back(type);
92  return success();
93  });
94 }
95 
96 /// Print allocate clause
98  OperandRange varsAllocate,
99  TypeRange typesAllocate,
100  OperandRange varsAllocator,
101  TypeRange typesAllocator) {
102  for (unsigned i = 0; i < varsAllocate.size(); ++i) {
103  std::string separator = i == varsAllocate.size() - 1 ? "" : ", ";
104  p << varsAllocator[i] << " : " << typesAllocator[i] << " -> ";
105  p << varsAllocate[i] << " : " << typesAllocate[i] << separator;
106  }
107 }
108 
109 //===----------------------------------------------------------------------===//
110 // Parser and printer for a clause attribute (StringEnumAttr)
111 //===----------------------------------------------------------------------===//
112 
113 template <typename ClauseAttr>
114 static ParseResult parseClauseAttr(AsmParser &parser, ClauseAttr &attr) {
115  using ClauseT = decltype(std::declval<ClauseAttr>().getValue());
116  StringRef enumStr;
117  SMLoc loc = parser.getCurrentLocation();
118  if (parser.parseKeyword(&enumStr))
119  return failure();
120  if (Optional<ClauseT> enumValue = symbolizeEnum<ClauseT>(enumStr)) {
121  attr = ClauseAttr::get(parser.getContext(), *enumValue);
122  return success();
123  }
124  return parser.emitError(loc, "invalid clause value: '") << enumStr << "'";
125 }
126 
127 template <typename ClauseAttr>
128 void printClauseAttr(OpAsmPrinter &p, Operation *op, ClauseAttr attr) {
129  p << stringifyEnum(attr.getValue());
130 }
131 
132 //===----------------------------------------------------------------------===//
133 // Parser and printer for Linear Clause
134 //===----------------------------------------------------------------------===//
135 
136 /// linear ::= `linear` `(` linear-list `)`
137 /// linear-list := linear-val | linear-val linear-list
138 /// linear-val := ssa-id-and-type `=` ssa-id-and-type
139 static ParseResult
142  SmallVectorImpl<Type> &types,
144  return parser.parseCommaSeparatedList([&]() {
146  Type type;
148  if (parser.parseOperand(var) || parser.parseEqual() ||
149  parser.parseOperand(stepVar) || parser.parseColonType(type))
150  return failure();
151 
152  vars.push_back(var);
153  types.push_back(type);
154  stepVars.push_back(stepVar);
155  return success();
156  });
157 }
158 
159 /// Print Linear Clause
161  ValueRange linearVars, TypeRange linearVarTypes,
162  ValueRange linearStepVars) {
163  size_t linearVarsSize = linearVars.size();
164  for (unsigned i = 0; i < linearVarsSize; ++i) {
165  std::string separator = i == linearVarsSize - 1 ? "" : ", ";
166  p << linearVars[i];
167  if (linearStepVars.size() > i)
168  p << " = " << linearStepVars[i];
169  p << " : " << linearVars[i].getType() << separator;
170  }
171 }
172 
173 //===----------------------------------------------------------------------===//
174 // Parser, verifier and printer for Aligned Clause
175 //===----------------------------------------------------------------------===//
177  Optional<ArrayAttr> alignmentValues,
178  OperandRange alignedVariables) {
179  // Check if number of alignment values equals to number of aligned variables
180  if (!alignedVariables.empty()) {
181  if (!alignmentValues || alignmentValues->size() != alignedVariables.size())
182  return op->emitOpError()
183  << "expected as many alignment values as aligned variables";
184  } else {
185  if (alignmentValues)
186  return op->emitOpError() << "unexpected alignment values attribute";
187  return success();
188  }
189 
190  // Check if each var is aligned only once - OpenMP 4.5 -> 2.8.1 section
191  DenseSet<Value> alignedItems;
192  for (auto it : alignedVariables)
193  if (!alignedItems.insert(it).second)
194  return op->emitOpError() << "aligned variable used more than once";
195 
196  if (!alignmentValues)
197  return success();
198 
199  // Check if all alignment values are positive - OpenMP 4.5 -> 2.8.1 section
200  for (unsigned i = 0; i < (*alignmentValues).size(); ++i) {
201  if (auto intAttr = (*alignmentValues)[i].dyn_cast<IntegerAttr>()) {
202  if (intAttr.getValue().sle(0))
203  return op->emitOpError() << "alignment should be greater than 0";
204  } else {
205  return op->emitOpError() << "expected integer alignment";
206  }
207  }
208 
209  return success();
210 }
211 
212 /// aligned ::= `aligned` `(` aligned-list `)`
213 /// aligned-list := aligned-val | aligned-val aligned-list
214 /// aligned-val := ssa-id-and-type `->` alignment
216  OpAsmParser &parser,
218  SmallVectorImpl<Type> &types, ArrayAttr &alignmentValues) {
219  SmallVector<Attribute> alignmentVec;
220  if (failed(parser.parseCommaSeparatedList([&]() {
221  if (parser.parseOperand(alignedItems.emplace_back()) ||
222  parser.parseColonType(types.emplace_back()) ||
223  parser.parseArrow() ||
224  parser.parseAttribute(alignmentVec.emplace_back())) {
225  return failure();
226  }
227  return success();
228  })))
229  return failure();
230  SmallVector<Attribute> alignments(alignmentVec.begin(), alignmentVec.end());
231  alignmentValues = ArrayAttr::get(parser.getContext(), alignments);
232  return success();
233 }
234 
235 /// Print Aligned Clause
237  ValueRange alignedVars,
238  TypeRange alignedVarTypes,
239  Optional<ArrayAttr> alignmentValues) {
240  for (unsigned i = 0; i < alignedVars.size(); ++i) {
241  if (i != 0)
242  p << ", ";
243  p << alignedVars[i] << " : " << alignedVars[i].getType();
244  p << " -> " << (*alignmentValues)[i];
245  }
246 }
247 
248 //===----------------------------------------------------------------------===//
249 // Parser, printer and verifier for Schedule Clause
250 //===----------------------------------------------------------------------===//
251 
252 static ParseResult
254  SmallVectorImpl<SmallString<12>> &modifiers) {
255  if (modifiers.size() > 2)
256  return parser.emitError(parser.getNameLoc()) << " unexpected modifier(s)";
257  for (const auto &mod : modifiers) {
258  // Translate the string. If it has no value, then it was not a valid
259  // modifier!
260  auto symbol = symbolizeScheduleModifier(mod);
261  if (!symbol)
262  return parser.emitError(parser.getNameLoc())
263  << " unknown modifier type: " << mod;
264  }
265 
266  // If we have one modifier that is "simd", then stick a "none" modiifer in
267  // index 0.
268  if (modifiers.size() == 1) {
269  if (symbolizeScheduleModifier(modifiers[0]) == ScheduleModifier::simd) {
270  modifiers.push_back(modifiers[0]);
271  modifiers[0] = stringifyScheduleModifier(ScheduleModifier::none);
272  }
273  } else if (modifiers.size() == 2) {
274  // If there are two modifier:
275  // First modifier should not be simd, second one should be simd
276  if (symbolizeScheduleModifier(modifiers[0]) == ScheduleModifier::simd ||
277  symbolizeScheduleModifier(modifiers[1]) != ScheduleModifier::simd)
278  return parser.emitError(parser.getNameLoc())
279  << " incorrect modifier order";
280  }
281  return success();
282 }
283 
284 /// schedule ::= `schedule` `(` sched-list `)`
285 /// sched-list ::= sched-val | sched-val sched-list |
286 /// sched-val `,` sched-modifier
287 /// sched-val ::= sched-with-chunk | sched-wo-chunk
288 /// sched-with-chunk ::= sched-with-chunk-types (`=` ssa-id-and-type)?
289 /// sched-with-chunk-types ::= `static` | `dynamic` | `guided`
290 /// sched-wo-chunk ::= `auto` | `runtime`
291 /// sched-modifier ::= sched-mod-val | sched-mod-val `,` sched-mod-val
292 /// sched-mod-val ::= `monotonic` | `nonmonotonic` | `simd` | `none`
294  OpAsmParser &parser, ClauseScheduleKindAttr &scheduleAttr,
295  ScheduleModifierAttr &scheduleModifier, UnitAttr &simdModifier,
296  Optional<OpAsmParser::UnresolvedOperand> &chunkSize, Type &chunkType) {
297  StringRef keyword;
298  if (parser.parseKeyword(&keyword))
299  return failure();
301  symbolizeClauseScheduleKind(keyword);
302  if (!schedule)
303  return parser.emitError(parser.getNameLoc()) << " expected schedule kind";
304 
305  scheduleAttr = ClauseScheduleKindAttr::get(parser.getContext(), *schedule);
306  switch (*schedule) {
307  case ClauseScheduleKind::Static:
308  case ClauseScheduleKind::Dynamic:
309  case ClauseScheduleKind::Guided:
310  if (succeeded(parser.parseOptionalEqual())) {
311  chunkSize = OpAsmParser::UnresolvedOperand{};
312  if (parser.parseOperand(*chunkSize) || parser.parseColonType(chunkType))
313  return failure();
314  } else {
315  chunkSize = std::nullopt;
316  }
317  break;
318  case ClauseScheduleKind::Auto:
320  chunkSize = std::nullopt;
321  }
322 
323  // If there is a comma, we have one or more modifiers..
324  SmallVector<SmallString<12>> modifiers;
325  while (succeeded(parser.parseOptionalComma())) {
326  StringRef mod;
327  if (parser.parseKeyword(&mod))
328  return failure();
329  modifiers.push_back(mod);
330  }
331 
332  if (verifyScheduleModifiers(parser, modifiers))
333  return failure();
334 
335  if (!modifiers.empty()) {
336  SMLoc loc = parser.getCurrentLocation();
338  symbolizeScheduleModifier(modifiers[0])) {
339  scheduleModifier = ScheduleModifierAttr::get(parser.getContext(), *mod);
340  } else {
341  return parser.emitError(loc, "invalid schedule modifier");
342  }
343  // Only SIMD attribute is allowed here!
344  if (modifiers.size() > 1) {
345  assert(symbolizeScheduleModifier(modifiers[1]) == ScheduleModifier::simd);
346  simdModifier = UnitAttr::get(parser.getBuilder().getContext());
347  }
348  }
349 
350  return success();
351 }
352 
353 /// Print schedule clause
355  ClauseScheduleKindAttr schedAttr,
356  ScheduleModifierAttr modifier, UnitAttr simd,
357  Value scheduleChunkVar,
358  Type scheduleChunkType) {
359  p << stringifyClauseScheduleKind(schedAttr.getValue());
360  if (scheduleChunkVar)
361  p << " = " << scheduleChunkVar << " : " << scheduleChunkVar.getType();
362  if (modifier)
363  p << ", " << stringifyScheduleModifier(modifier.getValue());
364  if (simd)
365  p << ", simd";
366 }
367 
368 //===----------------------------------------------------------------------===//
369 // Parser, printer and verifier for ReductionVarList
370 //===----------------------------------------------------------------------===//
371 
372 /// reduction-entry-list ::= reduction-entry
373 /// | reduction-entry-list `,` reduction-entry
374 /// reduction-entry ::= symbol-ref `->` ssa-id `:` type
375 static ParseResult
378  SmallVectorImpl<Type> &types,
379  ArrayAttr &redcuctionSymbols) {
380  SmallVector<SymbolRefAttr> reductionVec;
381  if (failed(parser.parseCommaSeparatedList([&]() {
382  if (parser.parseAttribute(reductionVec.emplace_back()) ||
383  parser.parseArrow() ||
384  parser.parseOperand(operands.emplace_back()) ||
385  parser.parseColonType(types.emplace_back()))
386  return failure();
387  return success();
388  })))
389  return failure();
390  SmallVector<Attribute> reductions(reductionVec.begin(), reductionVec.end());
391  redcuctionSymbols = ArrayAttr::get(parser.getContext(), reductions);
392  return success();
393 }
394 
395 /// Print Reduction clause
397  OperandRange reductionVars,
398  TypeRange reductionTypes,
399  Optional<ArrayAttr> reductions) {
400  for (unsigned i = 0, e = reductions->size(); i < e; ++i) {
401  if (i != 0)
402  p << ", ";
403  p << (*reductions)[i] << " -> " << reductionVars[i] << " : "
404  << reductionVars[i].getType();
405  }
406 }
407 
408 /// Verifies Reduction Clause
410  Optional<ArrayAttr> reductions,
411  OperandRange reductionVars) {
412  if (!reductionVars.empty()) {
413  if (!reductions || reductions->size() != reductionVars.size())
414  return op->emitOpError()
415  << "expected as many reduction symbol references "
416  "as reduction variables";
417  } else {
418  if (reductions)
419  return op->emitOpError() << "unexpected reduction symbol references";
420  return success();
421  }
422 
423  // TODO: The followings should be done in
424  // SymbolUserOpInterface::verifySymbolUses.
425  DenseSet<Value> accumulators;
426  for (auto args : llvm::zip(reductionVars, *reductions)) {
427  Value accum = std::get<0>(args);
428 
429  if (!accumulators.insert(accum).second)
430  return op->emitOpError() << "accumulator variable used more than once";
431 
432  Type varType = accum.getType().cast<PointerLikeType>();
433  auto symbolRef = std::get<1>(args).cast<SymbolRefAttr>();
434  auto decl =
435  SymbolTable::lookupNearestSymbolFrom<ReductionDeclareOp>(op, symbolRef);
436  if (!decl)
437  return op->emitOpError() << "expected symbol reference " << symbolRef
438  << " to point to a reduction declaration";
439 
440  if (decl.getAccumulatorType() && decl.getAccumulatorType() != varType)
441  return op->emitOpError()
442  << "expected accumulator (" << varType
443  << ") to be the same type as reduction declaration ("
444  << decl.getAccumulatorType() << ")";
445  }
446 
447  return success();
448 }
449 
450 //===----------------------------------------------------------------------===//
451 // Parser, printer and verifier for Synchronization Hint (2.17.12)
452 //===----------------------------------------------------------------------===//
453 
454 /// Parses a Synchronization Hint clause. The value of hint is an integer
455 /// which is a combination of different hints from `omp_sync_hint_t`.
456 ///
457 /// hint-clause = `hint` `(` hint-value `)`
459  IntegerAttr &hintAttr) {
460  StringRef hintKeyword;
461  int64_t hint = 0;
462  if (succeeded(parser.parseOptionalKeyword("none"))) {
463  hintAttr = IntegerAttr::get(parser.getBuilder().getI64Type(), 0);
464  return success();
465  }
466  auto parseKeyword = [&]() -> ParseResult {
467  if (failed(parser.parseKeyword(&hintKeyword)))
468  return failure();
469  if (hintKeyword == "uncontended")
470  hint |= 1;
471  else if (hintKeyword == "contended")
472  hint |= 2;
473  else if (hintKeyword == "nonspeculative")
474  hint |= 4;
475  else if (hintKeyword == "speculative")
476  hint |= 8;
477  else
478  return parser.emitError(parser.getCurrentLocation())
479  << hintKeyword << " is not a valid hint";
480  return success();
481  };
482  if (parser.parseCommaSeparatedList(parseKeyword))
483  return failure();
484  hintAttr = IntegerAttr::get(parser.getBuilder().getI64Type(), hint);
485  return success();
486 }
487 
488 /// Prints a Synchronization Hint clause
490  IntegerAttr hintAttr) {
491  int64_t hint = hintAttr.getInt();
492 
493  if (hint == 0) {
494  p << "none";
495  return;
496  }
497 
498  // Helper function to get n-th bit from the right end of `value`
499  auto bitn = [](int value, int n) -> bool { return value & (1 << n); };
500 
501  bool uncontended = bitn(hint, 0);
502  bool contended = bitn(hint, 1);
503  bool nonspeculative = bitn(hint, 2);
504  bool speculative = bitn(hint, 3);
505 
507  if (uncontended)
508  hints.push_back("uncontended");
509  if (contended)
510  hints.push_back("contended");
511  if (nonspeculative)
512  hints.push_back("nonspeculative");
513  if (speculative)
514  hints.push_back("speculative");
515 
516  llvm::interleaveComma(hints, p);
517 }
518 
519 /// Verifies a synchronization hint clause
521 
522  // Helper function to get n-th bit from the right end of `value`
523  auto bitn = [](int value, int n) -> bool { return value & (1 << n); };
524 
525  bool uncontended = bitn(hint, 0);
526  bool contended = bitn(hint, 1);
527  bool nonspeculative = bitn(hint, 2);
528  bool speculative = bitn(hint, 3);
529 
530  if (uncontended && contended)
531  return op->emitOpError() << "the hints omp_sync_hint_uncontended and "
532  "omp_sync_hint_contended cannot be combined";
533  if (nonspeculative && speculative)
534  return op->emitOpError() << "the hints omp_sync_hint_nonspeculative and "
535  "omp_sync_hint_speculative cannot be combined.";
536  return success();
537 }
538 
539 //===----------------------------------------------------------------------===//
540 // ParallelOp
541 //===----------------------------------------------------------------------===//
542 
543 void ParallelOp::build(OpBuilder &builder, OperationState &state,
544  ArrayRef<NamedAttribute> attributes) {
545  ParallelOp::build(
546  builder, state, /*if_expr_var=*/nullptr, /*num_threads_var=*/nullptr,
547  /*allocate_vars=*/ValueRange(), /*allocators_vars=*/ValueRange(),
548  /*reduction_vars=*/ValueRange(), /*reductions=*/nullptr,
549  /*proc_bind_val=*/nullptr);
550  state.addAttributes(attributes);
551 }
552 
554  if (getAllocateVars().size() != getAllocatorsVars().size())
555  return emitError(
556  "expected equal sizes for allocate and allocator variables");
557  return verifyReductionVarList(*this, getReductions(), getReductionVars());
558 }
559 
560 //===----------------------------------------------------------------------===//
561 // Verifier for SectionsOp
562 //===----------------------------------------------------------------------===//
563 
565  if (getAllocateVars().size() != getAllocatorsVars().size())
566  return emitError(
567  "expected equal sizes for allocate and allocator variables");
568 
569  return verifyReductionVarList(*this, getReductions(), getReductionVars());
570 }
571 
572 LogicalResult SectionsOp::verifyRegions() {
573  for (auto &inst : *getRegion().begin()) {
574  if (!(isa<SectionOp>(inst) || isa<TerminatorOp>(inst))) {
575  return emitOpError()
576  << "expected omp.section op or terminator op inside region";
577  }
578  }
579 
580  return success();
581 }
582 
584  // Check for allocate clause restrictions
585  if (getAllocateVars().size() != getAllocatorsVars().size())
586  return emitError(
587  "expected equal sizes for allocate and allocator variables");
588 
589  return success();
590 }
591 
592 //===----------------------------------------------------------------------===//
593 // WsLoopOp
594 //===----------------------------------------------------------------------===//
595 
596 /// loop-control ::= `(` ssa-id-list `)` `:` type `=` loop-bounds
597 /// loop-bounds := `(` ssa-id-list `)` to `(` ssa-id-list `)` inclusive? steps
598 /// steps := `step` `(`ssa-id-list`)`
604  SmallVectorImpl<Type> &loopVarTypes, UnitAttr &inclusive) {
605  // Parse an opening `(` followed by induction variables followed by `)`
607  Type loopVarType;
609  parser.parseColonType(loopVarType) ||
610  // Parse loop bounds.
611  parser.parseEqual() ||
612  parser.parseOperandList(lowerBound, ivs.size(),
614  parser.parseKeyword("to") ||
615  parser.parseOperandList(upperBound, ivs.size(),
617  return failure();
618 
619  if (succeeded(parser.parseOptionalKeyword("inclusive")))
620  inclusive = UnitAttr::get(parser.getBuilder().getContext());
621 
622  // Parse step values.
623  if (parser.parseKeyword("step") ||
624  parser.parseOperandList(steps, ivs.size(), OpAsmParser::Delimiter::Paren))
625  return failure();
626 
627  // Now parse the body.
628  loopVarTypes = SmallVector<Type>(ivs.size(), loopVarType);
629  for (auto &iv : ivs)
630  iv.type = loopVarType;
631  return parser.parseRegion(region, ivs);
632 }
633 
635  ValueRange lowerBound, ValueRange upperBound,
636  ValueRange steps, TypeRange loopVarTypes,
637  UnitAttr inclusive) {
638  auto args = region.front().getArguments();
639  p << " (" << args << ") : " << args[0].getType() << " = (" << lowerBound
640  << ") to (" << upperBound << ") ";
641  if (inclusive)
642  p << "inclusive ";
643  p << "step (" << steps << ") ";
644  p.printRegion(region, /*printEntryBlockArgs=*/false);
645 }
646 
647 //===----------------------------------------------------------------------===//
648 // Verifier for Simd construct [2.9.3.1]
649 //===----------------------------------------------------------------------===//
650 
652  if (this->getLowerBound().empty()) {
653  return emitOpError() << "empty lowerbound for simd loop operation";
654  }
655  if (this->getSimdlen().has_value() && this->getSafelen().has_value() &&
656  this->getSimdlen().value() > this->getSafelen().value()) {
657  return emitOpError()
658  << "simdlen clause and safelen clause are both present, but the "
659  "simdlen value is not less than or equal to safelen value";
660  }
661  return verifyAlignedClause(*this, this->getAlignmentValues(),
662  this->getAlignedVars());
663 }
664 
665 //===----------------------------------------------------------------------===//
666 // ReductionOp
667 //===----------------------------------------------------------------------===//
668 
670  Region &region) {
671  if (parser.parseOptionalKeyword("atomic"))
672  return success();
673  return parser.parseRegion(region);
674 }
675 
677  ReductionDeclareOp op, Region &region) {
678  if (region.empty())
679  return;
680  printer << "atomic ";
681  printer.printRegion(region);
682 }
683 
684 LogicalResult ReductionDeclareOp::verifyRegions() {
685  if (getInitializerRegion().empty())
686  return emitOpError() << "expects non-empty initializer region";
687  Block &initializerEntryBlock = getInitializerRegion().front();
688  if (initializerEntryBlock.getNumArguments() != 1 ||
689  initializerEntryBlock.getArgument(0).getType() != getType()) {
690  return emitOpError() << "expects initializer region with one argument "
691  "of the reduction type";
692  }
693 
694  for (YieldOp yieldOp : getInitializerRegion().getOps<YieldOp>()) {
695  if (yieldOp.getResults().size() != 1 ||
696  yieldOp.getResults().getTypes()[0] != getType())
697  return emitOpError() << "expects initializer region to yield a value "
698  "of the reduction type";
699  }
700 
701  if (getReductionRegion().empty())
702  return emitOpError() << "expects non-empty reduction region";
703  Block &reductionEntryBlock = getReductionRegion().front();
704  if (reductionEntryBlock.getNumArguments() != 2 ||
705  reductionEntryBlock.getArgumentTypes()[0] !=
706  reductionEntryBlock.getArgumentTypes()[1] ||
707  reductionEntryBlock.getArgumentTypes()[0] != getType())
708  return emitOpError() << "expects reduction region with two arguments of "
709  "the reduction type";
710  for (YieldOp yieldOp : getReductionRegion().getOps<YieldOp>()) {
711  if (yieldOp.getResults().size() != 1 ||
712  yieldOp.getResults().getTypes()[0] != getType())
713  return emitOpError() << "expects reduction region to yield a value "
714  "of the reduction type";
715  }
716 
717  if (getAtomicReductionRegion().empty())
718  return success();
719 
720  Block &atomicReductionEntryBlock = getAtomicReductionRegion().front();
721  if (atomicReductionEntryBlock.getNumArguments() != 2 ||
722  atomicReductionEntryBlock.getArgumentTypes()[0] !=
723  atomicReductionEntryBlock.getArgumentTypes()[1])
724  return emitOpError() << "expects atomic reduction region with two "
725  "arguments of the same type";
726  auto ptrType = atomicReductionEntryBlock.getArgumentTypes()[0]
727  .dyn_cast<PointerLikeType>();
728  if (!ptrType || ptrType.getElementType() != getType())
729  return emitOpError() << "expects atomic reduction region arguments to "
730  "be accumulators containing the reduction type";
731  return success();
732 }
733 
735  auto *op = (*this)->getParentWithTrait<ReductionClauseInterface::Trait>();
736  if (!op)
737  return emitOpError() << "must be used within an operation supporting "
738  "reduction clause interface";
739  while (op) {
740  for (const auto &var :
741  cast<ReductionClauseInterface>(op).getAllReductionVars())
742  if (var == getAccumulator())
743  return success();
744  op = op->getParentWithTrait<ReductionClauseInterface::Trait>();
745  }
746  return emitOpError() << "the accumulator is not used by the parent";
747 }
748 
749 //===----------------------------------------------------------------------===//
750 // TaskOp
751 //===----------------------------------------------------------------------===//
753  return verifyReductionVarList(*this, getInReductions(), getInReductionVars());
754 }
755 
756 //===----------------------------------------------------------------------===//
757 // TaskGroupOp
758 //===----------------------------------------------------------------------===//
760  return verifyReductionVarList(*this, getTaskReductions(),
761  getTaskReductionVars());
762 }
763 
764 //===----------------------------------------------------------------------===//
765 // TaskLoopOp
766 //===----------------------------------------------------------------------===//
767 SmallVector<Value> TaskLoopOp::getAllReductionVars() {
768  SmallVector<Value> allReductionNvars(getInReductionVars().begin(),
769  getInReductionVars().end());
770  allReductionNvars.insert(allReductionNvars.end(), getReductionVars().begin(),
771  getReductionVars().end());
772  return allReductionNvars;
773 }
774 
776  if (getAllocateVars().size() != getAllocatorsVars().size())
777  return emitError(
778  "expected equal sizes for allocate and allocator variables");
779  if (failed(
780  verifyReductionVarList(*this, getReductions(), getReductionVars())) ||
781  failed(verifyReductionVarList(*this, getInReductions(),
782  getInReductionVars())))
783  return failure();
784 
785  if (!getReductionVars().empty() && getNogroup())
786  return emitError("if a reduction clause is present on the taskloop "
787  "directive, the nogroup clause must not be specified");
788  for (auto var : getReductionVars()) {
789  if (llvm::is_contained(getInReductionVars(), var))
790  return emitError("the same list item cannot appear in both a reduction "
791  "and an in_reduction clause");
792  }
793 
794  if (getGrainSize() && getNumTasks()) {
795  return emitError(
796  "the grainsize clause and num_tasks clause are mutually exclusive and "
797  "may not appear on the same taskloop directive");
798  }
799  return success();
800 }
801 
802 //===----------------------------------------------------------------------===//
803 // WsLoopOp
804 //===----------------------------------------------------------------------===//
805 
806 void WsLoopOp::build(OpBuilder &builder, OperationState &state,
807  ValueRange lowerBound, ValueRange upperBound,
808  ValueRange step, ArrayRef<NamedAttribute> attributes) {
809  build(builder, state, lowerBound, upperBound, step,
810  /*linear_vars=*/ValueRange(),
811  /*linear_step_vars=*/ValueRange(), /*reduction_vars=*/ValueRange(),
812  /*reductions=*/nullptr, /*schedule_val=*/nullptr,
813  /*schedule_chunk_var=*/nullptr, /*schedule_modifier=*/nullptr,
814  /*simd_modifier=*/false, /*nowait=*/false, /*ordered_val=*/nullptr,
815  /*order_val=*/nullptr, /*inclusive=*/false);
816  state.addAttributes(attributes);
817 }
818 
820  return verifyReductionVarList(*this, getReductions(), getReductionVars());
821 }
822 
823 //===----------------------------------------------------------------------===//
824 // Verifier for critical construct (2.17.1)
825 //===----------------------------------------------------------------------===//
826 
828  return verifySynchronizationHint(*this, getHintVal());
829 }
830 
831 LogicalResult CriticalOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
832  if (getNameAttr()) {
833  SymbolRefAttr symbolRef = getNameAttr();
834  auto decl = symbolTable.lookupNearestSymbolFrom<CriticalDeclareOp>(
835  *this, symbolRef);
836  if (!decl) {
837  return emitOpError() << "expected symbol reference " << symbolRef
838  << " to point to a critical declaration";
839  }
840  }
841 
842  return success();
843 }
844 
845 //===----------------------------------------------------------------------===//
846 // Verifier for ordered construct
847 //===----------------------------------------------------------------------===//
848 
850  auto container = (*this)->getParentOfType<WsLoopOp>();
851  if (!container || !container.getOrderedValAttr() ||
852  container.getOrderedValAttr().getInt() == 0)
853  return emitOpError() << "ordered depend directive must be closely "
854  << "nested inside a worksharing-loop with ordered "
855  << "clause with parameter present";
856 
857  if (container.getOrderedValAttr().getInt() != (int64_t)*getNumLoopsVal())
858  return emitOpError() << "number of variables in depend clause does not "
859  << "match number of iteration variables in the "
860  << "doacross loop";
861 
862  return success();
863 }
864 
866  // TODO: The code generation for ordered simd directive is not supported yet.
867  if (getSimd())
868  return failure();
869 
870  if (auto container = (*this)->getParentOfType<WsLoopOp>()) {
871  if (!container.getOrderedValAttr() ||
872  container.getOrderedValAttr().getInt() != 0)
873  return emitOpError() << "ordered region must be closely nested inside "
874  << "a worksharing-loop region with an ordered "
875  << "clause without parameter present";
876  }
877 
878  return success();
879 }
880 
881 //===----------------------------------------------------------------------===//
882 // Verifier for AtomicReadOp
883 //===----------------------------------------------------------------------===//
884 
886  if (auto mo = getMemoryOrderVal()) {
887  if (*mo == ClauseMemoryOrderKind::Acq_rel ||
888  *mo == ClauseMemoryOrderKind::Release) {
889  return emitError(
890  "memory-order must not be acq_rel or release for atomic reads");
891  }
892  }
893  if (getX() == getV())
894  return emitError(
895  "read and write must not be to the same location for atomic reads");
896  return verifySynchronizationHint(*this, getHintVal());
897 }
898 
899 //===----------------------------------------------------------------------===//
900 // Verifier for AtomicWriteOp
901 //===----------------------------------------------------------------------===//
902 
904  if (auto mo = getMemoryOrderVal()) {
905  if (*mo == ClauseMemoryOrderKind::Acq_rel ||
906  *mo == ClauseMemoryOrderKind::Acquire) {
907  return emitError(
908  "memory-order must not be acq_rel or acquire for atomic writes");
909  }
910  }
911  if (getAddress().getType().cast<PointerLikeType>().getElementType() !=
912  getValue().getType())
913  return emitError("address must dereference to value type");
914  return verifySynchronizationHint(*this, getHintVal());
915 }
916 
917 //===----------------------------------------------------------------------===//
918 // Verifier for AtomicUpdateOp
919 //===----------------------------------------------------------------------===//
920 
921 bool AtomicUpdateOp::isNoOp() {
922  YieldOp yieldOp = dyn_cast<omp::YieldOp>(getFirstOp());
923  return (yieldOp &&
924  yieldOp.getResults().front() == getRegion().front().getArgument(0));
925 }
926 
927 Value AtomicUpdateOp::getWriteOpVal() {
928  YieldOp yieldOp = dyn_cast<omp::YieldOp>(getFirstOp());
929  if (yieldOp &&
930  yieldOp.getResults().front() != getRegion().front().getArgument(0))
931  return yieldOp.getResults().front();
932  return nullptr;
933 }
934 
935 LogicalResult AtomicUpdateOp::canonicalize(AtomicUpdateOp op,
936  PatternRewriter &rewriter) {
937  if (op.isNoOp()) {
938  rewriter.eraseOp(op);
939  return success();
940  }
941  if (Value writeVal = op.getWriteOpVal()) {
942  rewriter.replaceOpWithNewOp<AtomicWriteOp>(op, op.getX(), writeVal,
943  op.getHintValAttr(),
944  op.getMemoryOrderValAttr());
945  return success();
946  }
947  return failure();
948 }
949 
951  if (auto mo = getMemoryOrderVal()) {
952  if (*mo == ClauseMemoryOrderKind::Acq_rel ||
953  *mo == ClauseMemoryOrderKind::Acquire) {
954  return emitError(
955  "memory-order must not be acq_rel or acquire for atomic updates");
956  }
957  }
958 
959  if (getRegion().getNumArguments() != 1)
960  return emitError("the region must accept exactly one argument");
961 
962  if (getX().getType().cast<PointerLikeType>().getElementType() !=
963  getRegion().getArgument(0).getType()) {
964  return emitError("the type of the operand must be a pointer type whose "
965  "element type is the same as that of the region argument");
966  }
967 
968  return verifySynchronizationHint(*this, getHintVal());
969 }
970 
971 LogicalResult AtomicUpdateOp::verifyRegions() {
972 
973  YieldOp yieldOp = *getRegion().getOps<YieldOp>().begin();
974 
975  if (yieldOp.getResults().size() != 1)
976  return emitError("only updated value must be returned");
977  if (yieldOp.getResults().front().getType() !=
978  getRegion().getArgument(0).getType())
979  return emitError("input and yielded value must have the same type");
980  return success();
981 }
982 
983 //===----------------------------------------------------------------------===//
984 // Verifier for AtomicCaptureOp
985 //===----------------------------------------------------------------------===//
986 
987 Operation *AtomicCaptureOp::getFirstOp() {
988  return &getRegion().front().getOperations().front();
989 }
990 
991 Operation *AtomicCaptureOp::getSecondOp() {
992  auto &ops = getRegion().front().getOperations();
993  return ops.getNextNode(ops.front());
994 }
995 
996 AtomicReadOp AtomicCaptureOp::getAtomicReadOp() {
997  if (auto op = dyn_cast<AtomicReadOp>(getFirstOp()))
998  return op;
999  return dyn_cast<AtomicReadOp>(getSecondOp());
1000 }
1001 
1002 AtomicWriteOp AtomicCaptureOp::getAtomicWriteOp() {
1003  if (auto op = dyn_cast<AtomicWriteOp>(getFirstOp()))
1004  return op;
1005  return dyn_cast<AtomicWriteOp>(getSecondOp());
1006 }
1007 
1008 AtomicUpdateOp AtomicCaptureOp::getAtomicUpdateOp() {
1009  if (auto op = dyn_cast<AtomicUpdateOp>(getFirstOp()))
1010  return op;
1011  return dyn_cast<AtomicUpdateOp>(getSecondOp());
1012 }
1013 
1015  return verifySynchronizationHint(*this, getHintVal());
1016 }
1017 
1018 LogicalResult AtomicCaptureOp::verifyRegions() {
1019  Block::OpListType &ops = getRegion().front().getOperations();
1020  if (ops.size() != 3)
1021  return emitError()
1022  << "expected three operations in omp.atomic.capture region (one "
1023  "terminator, and two atomic ops)";
1024  auto &firstOp = ops.front();
1025  auto &secondOp = *ops.getNextNode(firstOp);
1026  auto firstReadStmt = dyn_cast<AtomicReadOp>(firstOp);
1027  auto firstUpdateStmt = dyn_cast<AtomicUpdateOp>(firstOp);
1028  auto secondReadStmt = dyn_cast<AtomicReadOp>(secondOp);
1029  auto secondUpdateStmt = dyn_cast<AtomicUpdateOp>(secondOp);
1030  auto secondWriteStmt = dyn_cast<AtomicWriteOp>(secondOp);
1031 
1032  if (!((firstUpdateStmt && secondReadStmt) ||
1033  (firstReadStmt && secondUpdateStmt) ||
1034  (firstReadStmt && secondWriteStmt)))
1035  return ops.front().emitError()
1036  << "invalid sequence of operations in the capture region";
1037  if (firstUpdateStmt && secondReadStmt &&
1038  firstUpdateStmt.getX() != secondReadStmt.getX())
1039  return firstUpdateStmt.emitError()
1040  << "updated variable in omp.atomic.update must be captured in "
1041  "second operation";
1042  if (firstReadStmt && secondUpdateStmt &&
1043  firstReadStmt.getX() != secondUpdateStmt.getX())
1044  return firstReadStmt.emitError()
1045  << "captured variable in omp.atomic.read must be updated in second "
1046  "operation";
1047  if (firstReadStmt && secondWriteStmt &&
1048  firstReadStmt.getX() != secondWriteStmt.getAddress())
1049  return firstReadStmt.emitError()
1050  << "captured variable in omp.atomic.read must be updated in "
1051  "second operation";
1052 
1053  if (getFirstOp()->getAttr("hint_val") || getSecondOp()->getAttr("hint_val"))
1054  return emitOpError(
1055  "operations inside capture region must not have hint clause");
1056 
1057  if (getFirstOp()->getAttr("memory_order_val") ||
1058  getSecondOp()->getAttr("memory_order_val"))
1059  return emitOpError(
1060  "operations inside capture region must not have memory_order clause");
1061  return success();
1062 }
1063 
1064 //===----------------------------------------------------------------------===//
1065 // Verifier for CancelOp
1066 //===----------------------------------------------------------------------===//
1067 
1069  ClauseCancellationConstructType cct = getCancellationConstructTypeVal();
1070  Operation *parentOp = (*this)->getParentOp();
1071 
1072  if (!parentOp) {
1073  return emitOpError() << "must be used within a region supporting "
1074  "cancel directive";
1075  }
1076 
1077  if ((cct == ClauseCancellationConstructType::Parallel) &&
1078  !isa<ParallelOp>(parentOp)) {
1079  return emitOpError() << "cancel parallel must appear "
1080  << "inside a parallel region";
1081  }
1082  if (cct == ClauseCancellationConstructType::Loop) {
1083  if (!isa<WsLoopOp>(parentOp)) {
1084  return emitOpError() << "cancel loop must appear "
1085  << "inside a worksharing-loop region";
1086  }
1087  if (cast<WsLoopOp>(parentOp).getNowaitAttr()) {
1088  return emitError() << "A worksharing construct that is canceled "
1089  << "must not have a nowait clause";
1090  }
1091  if (cast<WsLoopOp>(parentOp).getOrderedValAttr()) {
1092  return emitError() << "A worksharing construct that is canceled "
1093  << "must not have an ordered clause";
1094  }
1095 
1096  } else if (cct == ClauseCancellationConstructType::Sections) {
1097  if (!(isa<SectionsOp>(parentOp) || isa<SectionOp>(parentOp))) {
1098  return emitOpError() << "cancel sections must appear "
1099  << "inside a sections region";
1100  }
1101  if (isa_and_nonnull<SectionsOp>(parentOp->getParentOp()) &&
1102  cast<SectionsOp>(parentOp->getParentOp()).getNowaitAttr()) {
1103  return emitError() << "A sections construct that is canceled "
1104  << "must not have a nowait clause";
1105  }
1106  }
1107  // TODO : Add more when we support taskgroup.
1108  return success();
1109 }
1110 //===----------------------------------------------------------------------===//
1111 // Verifier for CancelOp
1112 //===----------------------------------------------------------------------===//
1113 
1115  ClauseCancellationConstructType cct = getCancellationConstructTypeVal();
1116  Operation *parentOp = (*this)->getParentOp();
1117 
1118  if (!parentOp) {
1119  return emitOpError() << "must be used within a region supporting "
1120  "cancellation point directive";
1121  }
1122 
1123  if ((cct == ClauseCancellationConstructType::Parallel) &&
1124  !(isa<ParallelOp>(parentOp))) {
1125  return emitOpError() << "cancellation point parallel must appear "
1126  << "inside a parallel region";
1127  }
1128  if ((cct == ClauseCancellationConstructType::Loop) &&
1129  !isa<WsLoopOp>(parentOp)) {
1130  return emitOpError() << "cancellation point loop must appear "
1131  << "inside a worksharing-loop region";
1132  }
1133  if ((cct == ClauseCancellationConstructType::Sections) &&
1134  !(isa<SectionsOp>(parentOp) || isa<SectionOp>(parentOp))) {
1135  return emitOpError() << "cancellation point sections must appear "
1136  << "inside a sections region";
1137  }
1138  // TODO : Add more when we support taskgroup.
1139  return success();
1140 }
1141 
1142 #define GET_ATTRDEF_CLASSES
1143 #include "mlir/Dialect/OpenMP/OpenMPOpsAttributes.cpp.inc"
1144 
1145 #define GET_OP_CLASSES
1146 #include "mlir/Dialect/OpenMP/OpenMPOps.cpp.inc"
static constexpr const bool value
void printClauseAttr(OpAsmPrinter &p, Operation *op, ClauseAttr attr)
static ParseResult parseScheduleClause(OpAsmParser &parser, ClauseScheduleKindAttr &scheduleAttr, ScheduleModifierAttr &scheduleModifier, UnitAttr &simdModifier, Optional< OpAsmParser::UnresolvedOperand > &chunkSize, Type &chunkType)
schedule ::= schedule ( sched-list ) sched-list ::= sched-val | sched-val sched-list | sched-val ,...
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...
ParseResult parseLoopControl(OpAsmParser &parser, Region &region, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &lowerBound, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &upperBound, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &steps, SmallVectorImpl< Type > &loopVarTypes, UnitAttr &inclusive)
loop-control ::= ( ssa-id-list ) : type = loop-bounds loop-bounds := ( ssa-id-list ) to ( ssa-id-list...
static ParseResult parseClauseAttr(AsmParser &parser, ClauseAttr &attr)
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 printReductionVarList(OpAsmPrinter &p, Operation *op, OperandRange reductionVars, TypeRange reductionTypes, Optional< ArrayAttr > reductions)
Print Reduction clause.
static void printAllocateAndAllocator(OpAsmPrinter &p, Operation *op, OperandRange varsAllocate, TypeRange typesAllocate, OperandRange varsAllocator, TypeRange typesAllocator)
Print allocate clause.
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.
static LogicalResult verifySynchronizationHint(Operation *op, uint64_t hint)
Verifies a synchronization hint clause.
static LogicalResult verifyAlignedClause(Operation *op, Optional< ArrayAttr > alignmentValues, OperandRange alignedVariables)
static void printAlignedClause(OpAsmPrinter &p, Operation *op, ValueRange alignedVars, TypeRange alignedVarTypes, Optional< ArrayAttr > alignmentValues)
Print Aligned Clause.
static void printSynchronizationHint(OpAsmPrinter &p, Operation *op, IntegerAttr hintAttr)
Prints a Synchronization Hint clause.
static void printAtomicReductionRegion(OpAsmPrinter &printer, ReductionDeclareOp op, Region &region)
static void printLinearClause(OpAsmPrinter &p, Operation *op, ValueRange linearVars, TypeRange linearVarTypes, ValueRange linearStepVars)
Print Linear Clause.
static ParseResult parseReductionVarList(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &operands, SmallVectorImpl< Type > &types, ArrayAttr &redcuctionSymbols)
reduction-entry-list ::= reduction-entry | reduction-entry-list , reduction-entry reduction-entry ::=...
static ParseResult verifyScheduleModifiers(OpAsmParser &parser, SmallVectorImpl< SmallString< 12 >> &modifiers)
void printLoopControl(OpAsmPrinter &p, Operation *op, Region &region, ValueRange lowerBound, ValueRange upperBound, ValueRange steps, TypeRange loopVarTypes, UnitAttr inclusive)
static LogicalResult verifyReductionVarList(Operation *op, Optional< ArrayAttr > reductions, OperandRange reductionVars)
Verifies Reduction Clause.
static void printScheduleClause(OpAsmPrinter &p, Operation *op, ClauseScheduleKindAttr schedAttr, ScheduleModifierAttr modifier, UnitAttr simd, Value scheduleChunkVar, Type scheduleChunkType)
Print schedule clause.
static ParseResult parseAtomicReductionRegion(OpAsmParser &parser, Region &region)
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:698
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 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:67
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
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 SMLoc getNameLoc() const =0
Return the location of the original name token.
virtual ParseResult parseArrow()=0
Parse a '->' token.
ParseResult parseKeyword(StringRef keyword)
Parse a given keyword.
Block represents an ordered list of Operations.
Definition: Block.h:30
ValueTypeRange< BlockArgListType > getArgumentTypes()
Return a range containing the types of the arguments for this block.
Definition: Block.cpp:137
BlockArgument getArgument(unsigned i)
Definition: Block.h:118
unsigned getNumArguments()
Definition: Block.h:117
BlockArgListType getArguments()
Definition: Block.h:76
Operation & front()
Definition: Block.h:142
llvm::iplist< Operation > OpListType
This is the list of operations in the block.
Definition: Block.h:125
IntegerType getI64Type()
Definition: Builders.cpp:70
MLIRContext * getContext() const
Definition: Builders.h:54
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.
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:198
This class implements the operand iterators for the Operation class.
Definition: ValueRange.h:41
type_range getType() const
Definition: ValueRange.cpp:30
Operation is a basic unit of execution within MLIR.
Definition: Operation.h:31
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Definition: Operation.h:165
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
Definition: Operation.cpp:512
This class represents success/failure for parsing-like operations that find it important to chain tog...
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
Definition: PatternMatch.h:610
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition: Region.h:26
bool empty()
Definition: Region.h:60
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)
Replaces the result op with a new op that is created without verification.
Definition: PatternMatch.h:451
This class represents a collection of SymbolTables.
Definition: SymbolTable.h:245
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
U cast() const
Definition: Types.h:280
This class provides an abstraction over the different types of ranges over Values.
Definition: ValueRange.h:349
type_range getType() const
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:85
Type getType() const
Return the type of this value.
Definition: Value.h:114
Runtime
Potential runtimes for AMD GPU kernels.
Definition: Runtimes.h:15
Include the generated interface declarations.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
bool succeeded(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a success value.
Definition: LogicalResult.h:68
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
Definition: Verifier.cpp:372
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
Definition: LogicalResult.h:72
int64_t mod(int64_t lhs, int64_t rhs)
Returns MLIR's mod operation on constants.
Definition: MathExtras.h:45
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
This is the representation of an operand reference.
This represents an operation in an abstracted form, suitable for use with the builder APIs.
void addAttributes(ArrayRef< NamedAttribute > newAttributes)
Add an array of named attributes.