MLIR  17.0.0git
Operation.cpp
Go to the documentation of this file.
1 //===- Operation.cpp - Operation support code -----------------------------===//
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 #include "mlir/IR/Operation.h"
10 #include "mlir/IR/BuiltinTypes.h"
11 #include "mlir/IR/Dialect.h"
12 #include "mlir/IR/IRMapping.h"
14 #include "mlir/IR/PatternMatch.h"
15 #include "mlir/IR/TypeUtilities.h"
17 #include "llvm/ADT/StringExtras.h"
18 #include <numeric>
19 
20 using namespace mlir;
21 
22 //===----------------------------------------------------------------------===//
23 // Operation
24 //===----------------------------------------------------------------------===//
25 
26 /// Create a new Operation from operation state.
28  return create(state.location, state.name, state.types, state.operands,
29  state.attributes.getDictionary(state.getContext()),
30  state.successors, state.regions);
31 }
32 
33 /// Create a new Operation with the specific fields.
35  TypeRange resultTypes, ValueRange operands,
36  NamedAttrList &&attributes, BlockRange successors,
37  RegionRange regions) {
38  unsigned numRegions = regions.size();
39  Operation *op = create(location, name, resultTypes, operands,
40  std::move(attributes), successors, numRegions);
41  for (unsigned i = 0; i < numRegions; ++i)
42  if (regions[i])
43  op->getRegion(i).takeBody(*regions[i]);
44  return op;
45 }
46 
47 /// Create a new Operation with the specific fields.
49  TypeRange resultTypes, ValueRange operands,
50  NamedAttrList &&attributes, BlockRange successors,
51  unsigned numRegions) {
52  // Populate default attributes.
53  name.populateDefaultAttrs(attributes);
54 
55  return create(location, name, resultTypes, operands,
56  attributes.getDictionary(location.getContext()), successors,
57  numRegions);
58 }
59 
60 /// Overload of create that takes an existing DictionaryAttr to avoid
61 /// unnecessarily uniquing a list of attributes.
63  TypeRange resultTypes, ValueRange operands,
64  DictionaryAttr attributes, BlockRange successors,
65  unsigned numRegions) {
66  assert(llvm::all_of(resultTypes, [](Type t) { return t; }) &&
67  "unexpected null result type");
68 
69  // We only need to allocate additional memory for a subset of results.
70  unsigned numTrailingResults = OpResult::getNumTrailing(resultTypes.size());
71  unsigned numInlineResults = OpResult::getNumInline(resultTypes.size());
72  unsigned numSuccessors = successors.size();
73  unsigned numOperands = operands.size();
74  unsigned numResults = resultTypes.size();
75 
76  // If the operation is known to have no operands, don't allocate an operand
77  // storage.
78  bool needsOperandStorage =
79  operands.empty() ? !name.hasTrait<OpTrait::ZeroOperands>() : true;
80 
81  // Compute the byte size for the operation and the operand storage. This takes
82  // into account the size of the operation, its trailing objects, and its
83  // prefixed objects.
84  size_t byteSize =
85  totalSizeToAlloc<detail::OperandStorage, BlockOperand, Region, OpOperand>(
86  needsOperandStorage ? 1 : 0, numSuccessors, numRegions, numOperands);
87  size_t prefixByteSize = llvm::alignTo(
88  Operation::prefixAllocSize(numTrailingResults, numInlineResults),
89  alignof(Operation));
90  char *mallocMem = reinterpret_cast<char *>(malloc(byteSize + prefixByteSize));
91  void *rawMem = mallocMem + prefixByteSize;
92 
93  // Create the new Operation.
94  Operation *op =
95  ::new (rawMem) Operation(location, name, numResults, numSuccessors,
96  numRegions, attributes, needsOperandStorage);
97 
98  assert((numSuccessors == 0 || op->mightHaveTrait<OpTrait::IsTerminator>()) &&
99  "unexpected successors in a non-terminator operation");
100 
101  // Initialize the results.
102  auto resultTypeIt = resultTypes.begin();
103  for (unsigned i = 0; i < numInlineResults; ++i, ++resultTypeIt)
104  new (op->getInlineOpResult(i)) detail::InlineOpResult(*resultTypeIt, i);
105  for (unsigned i = 0; i < numTrailingResults; ++i, ++resultTypeIt) {
106  new (op->getOutOfLineOpResult(i))
107  detail::OutOfLineOpResult(*resultTypeIt, i);
108  }
109 
110  // Initialize the regions.
111  for (unsigned i = 0; i != numRegions; ++i)
112  new (&op->getRegion(i)) Region(op);
113 
114  // Initialize the operands.
115  if (needsOperandStorage) {
116  new (&op->getOperandStorage()) detail::OperandStorage(
117  op, op->getTrailingObjects<OpOperand>(), operands);
118  }
119 
120  // Initialize the successors.
121  auto blockOperands = op->getBlockOperands();
122  for (unsigned i = 0; i != numSuccessors; ++i)
123  new (&blockOperands[i]) BlockOperand(op, successors[i]);
124 
125  return op;
126 }
127 
128 Operation::Operation(Location location, OperationName name, unsigned numResults,
129  unsigned numSuccessors, unsigned numRegions,
130  DictionaryAttr attributes, bool hasOperandStorage)
131  : location(location), numResults(numResults), numSuccs(numSuccessors),
132  numRegions(numRegions), hasOperandStorage(hasOperandStorage), name(name),
133  attrs(attributes) {
134  assert(attributes && "unexpected null attribute dictionary");
135 #ifndef NDEBUG
136  if (!getDialect() && !getContext()->allowsUnregisteredDialects())
137  llvm::report_fatal_error(
138  name.getStringRef() +
139  " created with unregistered dialect. If this is intended, please call "
140  "allowUnregisteredDialects() on the MLIRContext, or use "
141  "-allow-unregistered-dialect with the MLIR tool used.");
142 #endif
143 }
144 
145 // Operations are deleted through the destroy() member because they are
146 // allocated via malloc.
147 Operation::~Operation() {
148  assert(block == nullptr && "operation destroyed but still in a block");
149 #ifndef NDEBUG
150  if (!use_empty()) {
151  {
153  emitOpError("operation destroyed but still has uses");
154  for (Operation *user : getUsers())
155  diag.attachNote(user->getLoc()) << "- use: " << *user << "\n";
156  }
157  llvm::report_fatal_error("operation destroyed but still has uses");
158  }
159 #endif
160  // Explicitly run the destructors for the operands.
161  if (hasOperandStorage)
162  getOperandStorage().~OperandStorage();
163 
164  // Explicitly run the destructors for the successors.
165  for (auto &successor : getBlockOperands())
166  successor.~BlockOperand();
167 
168  // Explicitly destroy the regions.
169  for (auto &region : getRegions())
170  region.~Region();
171 }
172 
173 /// Destroy this operation or one of its subclasses.
175  // Operations may have additional prefixed allocation, which needs to be
176  // accounted for here when computing the address to free.
177  char *rawMem = reinterpret_cast<char *>(this) -
178  llvm::alignTo(prefixAllocSize(), alignof(Operation));
179  this->~Operation();
180  free(rawMem);
181 }
182 
183 /// Return true if this operation is a proper ancestor of the `other`
184 /// operation.
186  while ((other = other->getParentOp()))
187  if (this == other)
188  return true;
189  return false;
190 }
191 
192 /// Replace any uses of 'from' with 'to' within this operation.
194  if (from == to)
195  return;
196  for (auto &operand : getOpOperands())
197  if (operand.get() == from)
198  operand.set(to);
199 }
200 
201 /// Replace the current operands of this operation with the ones provided in
202 /// 'operands'.
204  if (LLVM_LIKELY(hasOperandStorage))
205  return getOperandStorage().setOperands(this, operands);
206  assert(operands.empty() && "setting operands without an operand storage");
207 }
208 
209 /// Replace the operands beginning at 'start' and ending at 'start' + 'length'
210 /// with the ones provided in 'operands'. 'operands' may be smaller or larger
211 /// than the range pointed to by 'start'+'length'.
212 void Operation::setOperands(unsigned start, unsigned length,
213  ValueRange operands) {
214  assert((start + length) <= getNumOperands() &&
215  "invalid operand range specified");
216  if (LLVM_LIKELY(hasOperandStorage))
217  return getOperandStorage().setOperands(this, start, length, operands);
218  assert(operands.empty() && "setting operands without an operand storage");
219 }
220 
221 /// Insert the given operands into the operand list at the given 'index'.
222 void Operation::insertOperands(unsigned index, ValueRange operands) {
223  if (LLVM_LIKELY(hasOperandStorage))
224  return setOperands(index, /*length=*/0, operands);
225  assert(operands.empty() && "inserting operands without an operand storage");
226 }
227 
228 //===----------------------------------------------------------------------===//
229 // Diagnostics
230 //===----------------------------------------------------------------------===//
231 
232 /// Emit an error about fatal conditions with this operation, reporting up to
233 /// any diagnostic handlers that may be listening.
236  if (getContext()->shouldPrintOpOnDiagnostic()) {
237  diag.attachNote(getLoc())
238  .append("see current operation: ")
239  .appendOp(*this, OpPrintingFlags().printGenericOpForm());
240  }
241  return diag;
242 }
243 
244 /// Emit a warning about this operation, reporting up to any diagnostic
245 /// handlers that may be listening.
248  if (getContext()->shouldPrintOpOnDiagnostic())
249  diag.attachNote(getLoc()) << "see current operation: " << *this;
250  return diag;
251 }
252 
253 /// Emit a remark about this operation, reporting up to any diagnostic
254 /// handlers that may be listening.
257  if (getContext()->shouldPrintOpOnDiagnostic())
258  diag.attachNote(getLoc()) << "see current operation: " << *this;
259  return diag;
260 }
261 
262 //===----------------------------------------------------------------------===//
263 // Operation Ordering
264 //===----------------------------------------------------------------------===//
265 
266 constexpr unsigned Operation::kInvalidOrderIdx;
267 constexpr unsigned Operation::kOrderStride;
268 
269 /// Given an operation 'other' that is within the same parent block, return
270 /// whether the current operation is before 'other' in the operation list
271 /// of the parent block.
272 /// Note: This function has an average complexity of O(1), but worst case may
273 /// take O(N) where N is the number of operations within the parent block.
275  assert(block && "Operations without parent blocks have no order.");
276  assert(other && other->block == block &&
277  "Expected other operation to have the same parent block.");
278  // If the order of the block is already invalid, directly recompute the
279  // parent.
280  if (!block->isOpOrderValid()) {
281  block->recomputeOpOrder();
282  } else {
283  // Update the order either operation if necessary.
284  updateOrderIfNecessary();
285  other->updateOrderIfNecessary();
286  }
287 
288  return orderIndex < other->orderIndex;
289 }
290 
291 /// Update the order index of this operation of this operation if necessary,
292 /// potentially recomputing the order of the parent block.
293 void Operation::updateOrderIfNecessary() {
294  assert(block && "expected valid parent");
295 
296  // If the order is valid for this operation there is nothing to do.
297  if (hasValidOrder())
298  return;
299  Operation *blockFront = &block->front();
300  Operation *blockBack = &block->back();
301 
302  // This method is expected to only be invoked on blocks with more than one
303  // operation.
304  assert(blockFront != blockBack && "expected more than one operation");
305 
306  // If the operation is at the end of the block.
307  if (this == blockBack) {
308  Operation *prevNode = getPrevNode();
309  if (!prevNode->hasValidOrder())
310  return block->recomputeOpOrder();
311 
312  // Add the stride to the previous operation.
313  orderIndex = prevNode->orderIndex + kOrderStride;
314  return;
315  }
316 
317  // If this is the first operation try to use the next operation to compute the
318  // ordering.
319  if (this == blockFront) {
320  Operation *nextNode = getNextNode();
321  if (!nextNode->hasValidOrder())
322  return block->recomputeOpOrder();
323  // There is no order to give this operation.
324  if (nextNode->orderIndex == 0)
325  return block->recomputeOpOrder();
326 
327  // If we can't use the stride, just take the middle value left. This is safe
328  // because we know there is at least one valid index to assign to.
329  if (nextNode->orderIndex <= kOrderStride)
330  orderIndex = (nextNode->orderIndex / 2);
331  else
332  orderIndex = kOrderStride;
333  return;
334  }
335 
336  // Otherwise, this operation is between two others. Place this operation in
337  // the middle of the previous and next if possible.
338  Operation *prevNode = getPrevNode(), *nextNode = getNextNode();
339  if (!prevNode->hasValidOrder() || !nextNode->hasValidOrder())
340  return block->recomputeOpOrder();
341  unsigned prevOrder = prevNode->orderIndex, nextOrder = nextNode->orderIndex;
342 
343  // Check to see if there is a valid order between the two.
344  if (prevOrder + 1 == nextOrder)
345  return block->recomputeOpOrder();
346  orderIndex = prevOrder + ((nextOrder - prevOrder) / 2);
347 }
348 
349 //===----------------------------------------------------------------------===//
350 // ilist_traits for Operation
351 //===----------------------------------------------------------------------===//
352 
353 auto llvm::ilist_detail::SpecificNodeAccess<
354  typename llvm::ilist_detail::compute_node_options<
355  ::mlir::Operation>::type>::getNodePtr(pointer n) -> node_type * {
356  return NodeAccess::getNodePtr<OptionsT>(n);
357 }
358 
359 auto llvm::ilist_detail::SpecificNodeAccess<
360  typename llvm::ilist_detail::compute_node_options<
361  ::mlir::Operation>::type>::getNodePtr(const_pointer n)
362  -> const node_type * {
363  return NodeAccess::getNodePtr<OptionsT>(n);
364 }
365 
366 auto llvm::ilist_detail::SpecificNodeAccess<
367  typename llvm::ilist_detail::compute_node_options<
368  ::mlir::Operation>::type>::getValuePtr(node_type *n) -> pointer {
369  return NodeAccess::getValuePtr<OptionsT>(n);
370 }
371 
372 auto llvm::ilist_detail::SpecificNodeAccess<
373  typename llvm::ilist_detail::compute_node_options<
374  ::mlir::Operation>::type>::getValuePtr(const node_type *n)
375  -> const_pointer {
376  return NodeAccess::getValuePtr<OptionsT>(n);
377 }
378 
380  op->destroy();
381 }
382 
383 Block *llvm::ilist_traits<::mlir::Operation>::getContainingBlock() {
384  size_t offset(size_t(&((Block *)nullptr->*Block::getSublistAccess(nullptr))));
385  iplist<Operation> *anchor(static_cast<iplist<Operation> *>(this));
386  return reinterpret_cast<Block *>(reinterpret_cast<char *>(anchor) - offset);
387 }
388 
389 /// This is a trait method invoked when an operation is added to a block. We
390 /// keep the block pointer up to date.
392  assert(!op->getBlock() && "already in an operation block!");
393  op->block = getContainingBlock();
394 
395  // Invalidate the order on the operation.
396  op->orderIndex = Operation::kInvalidOrderIdx;
397 }
398 
399 /// This is a trait method invoked when an operation is removed from a block.
400 /// We keep the block pointer up to date.
402  assert(op->block && "not already in an operation block!");
403  op->block = nullptr;
404 }
405 
406 /// This is a trait method invoked when an operation is moved from one block
407 /// to another. We keep the block pointer up to date.
409  ilist_traits<Operation> &otherList, op_iterator first, op_iterator last) {
410  Block *curParent = getContainingBlock();
411 
412  // Invalidate the ordering of the parent block.
413  curParent->invalidateOpOrder();
414 
415  // If we are transferring operations within the same block, the block
416  // pointer doesn't need to be updated.
417  if (curParent == otherList.getContainingBlock())
418  return;
419 
420  // Update the 'block' member of each operation.
421  for (; first != last; ++first)
422  first->block = curParent;
423 }
424 
425 /// Remove this operation (and its descendants) from its Block and delete
426 /// all of them.
428  if (auto *parent = getBlock())
429  parent->getOperations().erase(this);
430  else
431  destroy();
432 }
433 
434 /// Remove the operation from its parent block, but don't delete it.
436  if (Block *parent = getBlock())
437  parent->getOperations().remove(this);
438 }
439 
440 /// Unlink this operation from its current block and insert it right before
441 /// `existingOp` which may be in the same or another block in the same
442 /// function.
443 void Operation::moveBefore(Operation *existingOp) {
444  moveBefore(existingOp->getBlock(), existingOp->getIterator());
445 }
446 
447 /// Unlink this operation from its current basic block and insert it right
448 /// before `iterator` in the specified basic block.
450  llvm::iplist<Operation>::iterator iterator) {
451  block->getOperations().splice(iterator, getBlock()->getOperations(),
452  getIterator());
453 }
454 
455 /// Unlink this operation from its current block and insert it right after
456 /// `existingOp` which may be in the same or another block in the same function.
457 void Operation::moveAfter(Operation *existingOp) {
458  moveAfter(existingOp->getBlock(), existingOp->getIterator());
459 }
460 
461 /// Unlink this operation from its current block and insert it right after
462 /// `iterator` in the specified block.
464  llvm::iplist<Operation>::iterator iterator) {
465  assert(iterator != block->end() && "cannot move after end of block");
466  moveBefore(block, std::next(iterator));
467 }
468 
469 /// This drops all operand uses from this operation, which is an essential
470 /// step in breaking cyclic dependences between references when they are to
471 /// be deleted.
473  for (auto &op : getOpOperands())
474  op.drop();
475 
476  for (auto &region : getRegions())
477  region.dropAllReferences();
478 
479  for (auto &dest : getBlockOperands())
480  dest.drop();
481 }
482 
483 /// This drops all uses of any values defined by this operation or its nested
484 /// regions, wherever they are located.
486  dropAllUses();
487 
488  for (auto &region : getRegions())
489  for (auto &block : region)
490  block.dropAllDefinedValueUses();
491 }
492 
493 void Operation::setSuccessor(Block *block, unsigned index) {
494  assert(index < getNumSuccessors());
495  getBlockOperands()[index].set(block);
496 }
497 
498 /// Attempt to fold this operation using the Op's registered foldHook.
501  // If we have a registered operation definition matching this one, use it to
502  // try to constant fold the operation.
503  if (succeeded(name.foldHook(this, operands, results)))
504  return success();
505 
506  // Otherwise, fall back on the dialect hook to handle it.
507  Dialect *dialect = getDialect();
508  if (!dialect)
509  return failure();
510 
511  auto *interface = dyn_cast<DialectFoldInterface>(dialect);
512  if (!interface)
513  return failure();
514 
515  return interface->fold(this, operands, results);
516 }
517 
518 /// Emit an error with the op name prefixed, like "'dim' op " which is
519 /// convenient for verifiers.
521  return emitError() << "'" << getName() << "' op " << message;
522 }
523 
524 //===----------------------------------------------------------------------===//
525 // Operation Cloning
526 //===----------------------------------------------------------------------===//
527 
529  : cloneRegionsFlag(false), cloneOperandsFlag(false) {}
530 
531 Operation::CloneOptions::CloneOptions(bool cloneRegions, bool cloneOperands)
532  : cloneRegionsFlag(cloneRegions), cloneOperandsFlag(cloneOperands) {}
533 
536 }
537 
539  cloneRegionsFlag = enable;
540  return *this;
541 }
542 
544  cloneOperandsFlag = enable;
545  return *this;
546 }
547 
548 /// Create a deep copy of this operation but keep the operation regions empty.
549 /// Operands are remapped using `mapper` (if present), and `mapper` is updated
550 /// to contain the results. The `mapResults` flag specifies whether the results
551 /// of the cloned operation should be added to the map.
553  return clone(mapper, CloneOptions::all().cloneRegions(false));
554 }
555 
557  IRMapping mapper;
558  return cloneWithoutRegions(mapper);
559 }
560 
561 /// Create a deep copy of this operation, remapping any operands that use
562 /// values outside of the operation using the map that is provided (leaving
563 /// them alone if no entry is present). Replaces references to cloned
564 /// sub-operations to the corresponding operation that is copied, and adds
565 /// those mappings to the map.
567  SmallVector<Value, 8> operands;
568  SmallVector<Block *, 2> successors;
569 
570  // Remap the operands.
571  if (options.shouldCloneOperands()) {
572  operands.reserve(getNumOperands());
573  for (auto opValue : getOperands())
574  operands.push_back(mapper.lookupOrDefault(opValue));
575  }
576 
577  // Remap the successors.
578  successors.reserve(getNumSuccessors());
579  for (Block *successor : getSuccessors())
580  successors.push_back(mapper.lookupOrDefault(successor));
581 
582  // Create the new operation.
583  auto *newOp = create(getLoc(), getName(), getResultTypes(), operands, attrs,
584  successors, getNumRegions());
585  mapper.map(this, newOp);
586 
587  // Clone the regions.
588  if (options.shouldCloneRegions()) {
589  for (unsigned i = 0; i != numRegions; ++i)
590  getRegion(i).cloneInto(&newOp->getRegion(i), mapper);
591  }
592 
593  // Remember the mapping of any results.
594  for (unsigned i = 0, e = getNumResults(); i != e; ++i)
595  mapper.map(getResult(i), newOp->getResult(i));
596 
597  return newOp;
598 }
599 
601  IRMapping mapper;
602  return clone(mapper, options);
603 }
604 
605 //===----------------------------------------------------------------------===//
606 // OpState trait class.
607 //===----------------------------------------------------------------------===//
608 
609 // The fallback for the parser is to try for a dialect operation parser.
610 // Otherwise, reject the custom assembly form.
612  if (auto parseFn = result.name.getDialect()->getParseOperationHook(
613  result.name.getStringRef()))
614  return (*parseFn)(parser, result);
615  return parser.emitError(parser.getNameLoc(), "has no custom assembly form");
616 }
617 
618 // The fallback for the printer is to try for a dialect operation printer.
619 // Otherwise, it prints the generic form.
620 void OpState::print(Operation *op, OpAsmPrinter &p, StringRef defaultDialect) {
621  if (auto printFn = op->getDialect()->getOperationPrinter(op)) {
622  printOpName(op, p, defaultDialect);
623  printFn(op, p);
624  } else {
625  p.printGenericOp(op);
626  }
627 }
628 
629 /// Print an operation name, eliding the dialect prefix if necessary and doesn't
630 /// lead to ambiguities.
632  StringRef defaultDialect) {
633  StringRef name = op->getName().getStringRef();
634  if (name.startswith((defaultDialect + ".").str()) && name.count('.') == 1)
635  name = name.drop_front(defaultDialect.size() + 1);
636  p.getStream() << name;
637 }
638 
639 /// Emit an error about fatal conditions with this operation, reporting up to
640 /// any diagnostic handlers that may be listening.
641 InFlightDiagnostic OpState::emitError(const Twine &message) {
642  return getOperation()->emitError(message);
643 }
644 
645 /// Emit an error with the op name prefixed, like "'dim' op " which is
646 /// convenient for verifiers.
648  return getOperation()->emitOpError(message);
649 }
650 
651 /// Emit a warning about this operation, reporting up to any diagnostic
652 /// handlers that may be listening.
654  return getOperation()->emitWarning(message);
655 }
656 
657 /// Emit a remark about this operation, reporting up to any diagnostic
658 /// handlers that may be listening.
660  return getOperation()->emitRemark(message);
661 }
662 
663 //===----------------------------------------------------------------------===//
664 // Op Trait implementations
665 //===----------------------------------------------------------------------===//
666 
668  if (op->getNumOperands() == 1) {
669  auto *argumentOp = op->getOperand(0).getDefiningOp();
670  if (argumentOp && op->getName() == argumentOp->getName()) {
671  // Replace the outer operation output with the inner operation.
672  return op->getOperand(0);
673  }
674  } else if (op->getOperand(0) == op->getOperand(1)) {
675  return op->getOperand(0);
676  }
677 
678  return {};
679 }
680 
682  auto *argumentOp = op->getOperand(0).getDefiningOp();
683  if (argumentOp && op->getName() == argumentOp->getName()) {
684  // Replace the outer involutions output with inner's input.
685  return argumentOp->getOperand(0);
686  }
687 
688  return {};
689 }
690 
692  if (op->getNumOperands() != 0)
693  return op->emitOpError() << "requires zero operands";
694  return success();
695 }
696 
698  if (op->getNumOperands() != 1)
699  return op->emitOpError() << "requires a single operand";
700  return success();
701 }
702 
704  unsigned numOperands) {
705  if (op->getNumOperands() != numOperands) {
706  return op->emitOpError() << "expected " << numOperands
707  << " operands, but found " << op->getNumOperands();
708  }
709  return success();
710 }
711 
713  unsigned numOperands) {
714  if (op->getNumOperands() < numOperands)
715  return op->emitOpError()
716  << "expected " << numOperands << " or more operands, but found "
717  << op->getNumOperands();
718  return success();
719 }
720 
721 /// If this is a vector type, or a tensor type, return the scalar element type
722 /// that it is built around, otherwise return the type unmodified.
724  if (auto vec = type.dyn_cast<VectorType>())
725  return vec.getElementType();
726 
727  // Look through tensor<vector<...>> to find the underlying element type.
728  if (auto tensor = type.dyn_cast<TensorType>())
729  return getTensorOrVectorElementType(tensor.getElementType());
730  return type;
731 }
732 
734  // FIXME: Add back check for no side effects on operation.
735  // Currently adding it would cause the shared library build
736  // to fail since there would be a dependency of IR on SideEffectInterfaces
737  // which is cyclical.
738  return success();
739 }
740 
742  // FIXME: Add back check for no side effects on operation.
743  // Currently adding it would cause the shared library build
744  // to fail since there would be a dependency of IR on SideEffectInterfaces
745  // which is cyclical.
746  return success();
747 }
748 
751  for (auto opType : op->getOperandTypes()) {
752  auto type = getTensorOrVectorElementType(opType);
753  if (!type.isSignlessIntOrIndex())
754  return op->emitOpError() << "requires an integer or index type";
755  }
756  return success();
757 }
758 
760  for (auto opType : op->getOperandTypes()) {
761  auto type = getTensorOrVectorElementType(opType);
762  if (!type.isa<FloatType>())
763  return op->emitOpError("requires a float type");
764  }
765  return success();
766 }
767 
769  // Zero or one operand always have the "same" type.
770  unsigned nOperands = op->getNumOperands();
771  if (nOperands < 2)
772  return success();
773 
774  auto type = op->getOperand(0).getType();
775  for (auto opType : llvm::drop_begin(op->getOperandTypes(), 1))
776  if (opType != type)
777  return op->emitOpError() << "requires all operands to have the same type";
778  return success();
779 }
780 
782  if (op->getNumRegions() != 0)
783  return op->emitOpError() << "requires zero regions";
784  return success();
785 }
786 
788  if (op->getNumRegions() != 1)
789  return op->emitOpError() << "requires one region";
790  return success();
791 }
792 
794  unsigned numRegions) {
795  if (op->getNumRegions() != numRegions)
796  return op->emitOpError() << "expected " << numRegions << " regions";
797  return success();
798 }
799 
801  unsigned numRegions) {
802  if (op->getNumRegions() < numRegions)
803  return op->emitOpError() << "expected " << numRegions << " or more regions";
804  return success();
805 }
806 
808  if (op->getNumResults() != 0)
809  return op->emitOpError() << "requires zero results";
810  return success();
811 }
812 
814  if (op->getNumResults() != 1)
815  return op->emitOpError() << "requires one result";
816  return success();
817 }
818 
820  unsigned numOperands) {
821  if (op->getNumResults() != numOperands)
822  return op->emitOpError() << "expected " << numOperands << " results";
823  return success();
824 }
825 
827  unsigned numOperands) {
828  if (op->getNumResults() < numOperands)
829  return op->emitOpError()
830  << "expected " << numOperands << " or more results";
831  return success();
832 }
833 
835  if (failed(verifyAtLeastNOperands(op, 1)))
836  return failure();
837 
839  return op->emitOpError() << "requires the same shape for all operands";
840 
841  return success();
842 }
843 
845  if (failed(verifyAtLeastNOperands(op, 1)) ||
847  return failure();
848 
850  types.append(llvm::to_vector<4>(op->getResultTypes()));
851 
852  if (failed(verifyCompatibleShapes(types)))
853  return op->emitOpError()
854  << "requires the same shape for all operands and results";
855 
856  return success();
857 }
858 
860  if (failed(verifyAtLeastNOperands(op, 1)))
861  return failure();
862  auto elementType = getElementTypeOrSelf(op->getOperand(0));
863 
864  for (auto operand : llvm::drop_begin(op->getOperands(), 1)) {
865  if (getElementTypeOrSelf(operand) != elementType)
866  return op->emitOpError("requires the same element type for all operands");
867  }
868 
869  return success();
870 }
871 
874  if (failed(verifyAtLeastNOperands(op, 1)) ||
876  return failure();
877 
878  auto elementType = getElementTypeOrSelf(op->getResult(0));
879 
880  // Verify result element type matches first result's element type.
881  for (auto result : llvm::drop_begin(op->getResults(), 1)) {
882  if (getElementTypeOrSelf(result) != elementType)
883  return op->emitOpError(
884  "requires the same element type for all operands and results");
885  }
886 
887  // Verify operand's element type matches first result's element type.
888  for (auto operand : op->getOperands()) {
889  if (getElementTypeOrSelf(operand) != elementType)
890  return op->emitOpError(
891  "requires the same element type for all operands and results");
892  }
893 
894  return success();
895 }
896 
898  if (failed(verifyAtLeastNOperands(op, 1)) ||
900  return failure();
901 
902  auto type = op->getResult(0).getType();
903  auto elementType = getElementTypeOrSelf(type);
904  Attribute encoding = nullptr;
905  if (auto rankedType = dyn_cast<RankedTensorType>(type))
906  encoding = rankedType.getEncoding();
907  for (auto resultType : llvm::drop_begin(op->getResultTypes())) {
908  if (getElementTypeOrSelf(resultType) != elementType ||
909  failed(verifyCompatibleShape(resultType, type)))
910  return op->emitOpError()
911  << "requires the same type for all operands and results";
912  if (encoding)
913  if (auto rankedType = dyn_cast<RankedTensorType>(resultType);
914  encoding != rankedType.getEncoding())
915  return op->emitOpError()
916  << "requires the same encoding for all operands and results";
917  }
918  for (auto opType : op->getOperandTypes()) {
919  if (getElementTypeOrSelf(opType) != elementType ||
920  failed(verifyCompatibleShape(opType, type)))
921  return op->emitOpError()
922  << "requires the same type for all operands and results";
923  if (encoding)
924  if (auto rankedType = dyn_cast<RankedTensorType>(opType);
925  encoding != rankedType.getEncoding())
926  return op->emitOpError()
927  << "requires the same encoding for all operands and results";
928  }
929  return success();
930 }
931 
933  Block *block = op->getBlock();
934  // Verify that the operation is at the end of the respective parent block.
935  if (!block || &block->back() != op)
936  return op->emitOpError("must be the last operation in the parent block");
937  return success();
938 }
939 
941  auto *parent = op->getParentRegion();
942 
943  // Verify that the operands lines up with the BB arguments in the successor.
944  for (Block *succ : op->getSuccessors())
945  if (succ->getParent() != parent)
946  return op->emitError("reference to block defined in another region");
947  return success();
948 }
949 
951  if (op->getNumSuccessors() != 0) {
952  return op->emitOpError("requires 0 successors but found ")
953  << op->getNumSuccessors();
954  }
955  return success();
956 }
957 
959  if (op->getNumSuccessors() != 1) {
960  return op->emitOpError("requires 1 successor but found ")
961  << op->getNumSuccessors();
962  }
963  return verifyTerminatorSuccessors(op);
964 }
966  unsigned numSuccessors) {
967  if (op->getNumSuccessors() != numSuccessors) {
968  return op->emitOpError("requires ")
969  << numSuccessors << " successors but found "
970  << op->getNumSuccessors();
971  }
972  return verifyTerminatorSuccessors(op);
973 }
975  unsigned numSuccessors) {
976  if (op->getNumSuccessors() < numSuccessors) {
977  return op->emitOpError("requires at least ")
978  << numSuccessors << " successors but found "
979  << op->getNumSuccessors();
980  }
981  return verifyTerminatorSuccessors(op);
982 }
983 
985  for (auto resultType : op->getResultTypes()) {
986  auto elementType = getTensorOrVectorElementType(resultType);
987  bool isBoolType = elementType.isInteger(1);
988  if (!isBoolType)
989  return op->emitOpError() << "requires a bool result type";
990  }
991 
992  return success();
993 }
994 
996  for (auto resultType : op->getResultTypes())
997  if (!getTensorOrVectorElementType(resultType).isa<FloatType>())
998  return op->emitOpError() << "requires a floating point type";
999 
1000  return success();
1001 }
1002 
1005  for (auto resultType : op->getResultTypes())
1006  if (!getTensorOrVectorElementType(resultType).isSignlessIntOrIndex())
1007  return op->emitOpError() << "requires an integer or index type";
1008  return success();
1009 }
1010 
1012  StringRef attrName,
1013  StringRef valueGroupName,
1014  size_t expectedCount) {
1015  auto sizeAttr = op->getAttrOfType<DenseI32ArrayAttr>(attrName);
1016  if (!sizeAttr)
1017  return op->emitOpError("requires dense i32 array attribute '")
1018  << attrName << "'";
1019 
1020  ArrayRef<int32_t> sizes = sizeAttr.asArrayRef();
1021  if (llvm::any_of(sizes, [](int32_t element) { return element < 0; }))
1022  return op->emitOpError("'")
1023  << attrName << "' attribute cannot have negative elements";
1024 
1025  size_t totalCount =
1026  std::accumulate(sizes.begin(), sizes.end(), 0,
1027  [](unsigned all, int32_t one) { return all + one; });
1028 
1029  if (totalCount != expectedCount)
1030  return op->emitOpError()
1031  << valueGroupName << " count (" << expectedCount
1032  << ") does not match with the total size (" << totalCount
1033  << ") specified in attribute '" << attrName << "'";
1034  return success();
1035 }
1036 
1038  StringRef attrName) {
1039  return verifyValueSizeAttr(op, attrName, "operand", op->getNumOperands());
1040 }
1041 
1043  StringRef attrName) {
1044  return verifyValueSizeAttr(op, attrName, "result", op->getNumResults());
1045 }
1046 
1048  for (Region &region : op->getRegions()) {
1049  if (region.empty())
1050  continue;
1051 
1052  if (region.getNumArguments() != 0) {
1053  if (op->getNumRegions() > 1)
1054  return op->emitOpError("region #")
1055  << region.getRegionNumber() << " should have no arguments";
1056  return op->emitOpError("region should have no arguments");
1057  }
1058  }
1059  return success();
1060 }
1061 
1063  auto isMappableType = [](Type type) {
1064  return type.isa<VectorType, TensorType>();
1065  };
1066  auto resultMappableTypes = llvm::to_vector<1>(
1067  llvm::make_filter_range(op->getResultTypes(), isMappableType));
1068  auto operandMappableTypes = llvm::to_vector<2>(
1069  llvm::make_filter_range(op->getOperandTypes(), isMappableType));
1070 
1071  // If the op only has scalar operand/result types, then we have nothing to
1072  // check.
1073  if (resultMappableTypes.empty() && operandMappableTypes.empty())
1074  return success();
1075 
1076  if (!resultMappableTypes.empty() && operandMappableTypes.empty())
1077  return op->emitOpError("if a result is non-scalar, then at least one "
1078  "operand must be non-scalar");
1079 
1080  assert(!operandMappableTypes.empty());
1081 
1082  if (resultMappableTypes.empty())
1083  return op->emitOpError("if an operand is non-scalar, then there must be at "
1084  "least one non-scalar result");
1085 
1086  if (resultMappableTypes.size() != op->getNumResults())
1087  return op->emitOpError(
1088  "if an operand is non-scalar, then all results must be non-scalar");
1089 
1090  SmallVector<Type, 4> types = llvm::to_vector<2>(
1091  llvm::concat<Type>(operandMappableTypes, resultMappableTypes));
1092  TypeID expectedBaseTy = types.front().getTypeID();
1093  if (!llvm::all_of(types,
1094  [&](Type t) { return t.getTypeID() == expectedBaseTy; }) ||
1095  failed(verifyCompatibleShapes(types))) {
1096  return op->emitOpError() << "all non-scalar operands/results must have the "
1097  "same shape and base type";
1098  }
1099 
1100  return success();
1101 }
1102 
1103 /// Check for any values used by operations regions attached to the
1104 /// specified "IsIsolatedFromAbove" operation defined outside of it.
1106  assert(isolatedOp->hasTrait<OpTrait::IsIsolatedFromAbove>() &&
1107  "Intended to check IsolatedFromAbove ops");
1108 
1109  // List of regions to analyze. Each region is processed independently, with
1110  // respect to the common `limit` region, so we can look at them in any order.
1111  // Therefore, use a simple vector and push/pop back the current region.
1112  SmallVector<Region *, 8> pendingRegions;
1113  for (auto &region : isolatedOp->getRegions()) {
1114  pendingRegions.push_back(&region);
1115 
1116  // Traverse all operations in the region.
1117  while (!pendingRegions.empty()) {
1118  for (Operation &op : pendingRegions.pop_back_val()->getOps()) {
1119  for (Value operand : op.getOperands()) {
1120  // Check that any value that is used by an operation is defined in the
1121  // same region as either an operation result.
1122  auto *operandRegion = operand.getParentRegion();
1123  if (!operandRegion)
1124  return op.emitError("operation's operand is unlinked");
1125  if (!region.isAncestor(operandRegion)) {
1126  return op.emitOpError("using value defined outside the region")
1127  .attachNote(isolatedOp->getLoc())
1128  << "required by region isolation constraints";
1129  }
1130  }
1131 
1132  // Schedule any regions in the operation for further checking. Don't
1133  // recurse into other IsolatedFromAbove ops, because they will check
1134  // themselves.
1135  if (op.getNumRegions() &&
1136  !op.hasTrait<OpTrait::IsIsolatedFromAbove>()) {
1137  for (Region &subRegion : op.getRegions())
1138  pendingRegions.push_back(&subRegion);
1139  }
1140  }
1141  }
1142  }
1143 
1144  return success();
1145 }
1146 
1148  return op->hasTrait<Elementwise>() && op->hasTrait<Scalarizable>() &&
1149  op->hasTrait<Vectorizable>() && op->hasTrait<Tensorizable>();
1150 }
1151 
1152 //===----------------------------------------------------------------------===//
1153 // CastOpInterface
1154 //===----------------------------------------------------------------------===//
1155 
1156 /// Attempt to fold the given cast operation.
1159  SmallVectorImpl<OpFoldResult> &foldResults) {
1160  OperandRange operands = op->getOperands();
1161  if (operands.empty())
1162  return failure();
1163  ResultRange results = op->getResults();
1164 
1165  // Check for the case where the input and output types match 1-1.
1166  if (operands.getTypes() == results.getTypes()) {
1167  foldResults.append(operands.begin(), operands.end());
1168  return success();
1169  }
1170 
1171  return failure();
1172 }
1173 
1174 /// Attempt to verify the given cast operation.
1176  Operation *op, function_ref<bool(TypeRange, TypeRange)> areCastCompatible) {
1177  auto resultTypes = op->getResultTypes();
1178  if (resultTypes.empty())
1179  return op->emitOpError()
1180  << "expected at least one result for cast operation";
1181 
1182  auto operandTypes = op->getOperandTypes();
1183  if (!areCastCompatible(operandTypes, resultTypes)) {
1184  InFlightDiagnostic diag = op->emitOpError("operand type");
1185  if (operandTypes.empty())
1186  diag << "s []";
1187  else if (llvm::size(operandTypes) == 1)
1188  diag << " " << *operandTypes.begin();
1189  else
1190  diag << "s " << operandTypes;
1191  return diag << " and result type" << (resultTypes.size() == 1 ? " " : "s ")
1192  << resultTypes << " are cast incompatible";
1193  }
1194 
1195  return success();
1196 }
1197 
1198 //===----------------------------------------------------------------------===//
1199 // Misc. utils
1200 //===----------------------------------------------------------------------===//
1201 
1202 /// Insert an operation, generated by `buildTerminatorOp`, at the end of the
1203 /// region's only block if it does not have a terminator already. If the region
1204 /// is empty, insert a new block first. `buildTerminatorOp` should return the
1205 /// terminator operation to insert.
1207  Region &region, OpBuilder &builder, Location loc,
1208  function_ref<Operation *(OpBuilder &, Location)> buildTerminatorOp) {
1209  OpBuilder::InsertionGuard guard(builder);
1210  if (region.empty())
1211  builder.createBlock(&region);
1212 
1213  Block &block = region.back();
1214  if (!block.empty() && block.back().hasTrait<OpTrait::IsTerminator>())
1215  return;
1216 
1217  builder.setInsertionPointToEnd(&block);
1218  builder.insert(buildTerminatorOp(builder, loc));
1219 }
1220 
1221 /// Create a simple OpBuilder and forward to the OpBuilder version of this
1222 /// function.
1224  Region &region, Builder &builder, Location loc,
1225  function_ref<Operation *(OpBuilder &, Location)> buildTerminatorOp) {
1226  OpBuilder opBuilder(builder.getContext());
1227  ensureRegionTerminator(region, opBuilder, loc, buildTerminatorOp);
1228 }
static LogicalResult verifyTerminatorSuccessors(Operation *op)
Definition: Operation.cpp:940
static Type getTensorOrVectorElementType(Type type)
If this is a vector type, or a tensor type, return the scalar element type that it is built around,...
Definition: Operation.cpp:723
static std::string diag(const llvm::Value &value)
static llvm::ManagedStatic< PassManagerOptions > options
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
virtual SMLoc getNameLoc() const =0
Return the location of the original name token.
virtual raw_ostream & getStream() const
Return the raw output stream used by this printer.
Attributes are known-constant values of operations.
Definition: Attributes.h:25
A block operand represents an operand that holds a reference to a Block, e.g.
Definition: BlockSupport.h:30
This class provides an abstraction over the different types of ranges over Blocks.
Definition: BlockSupport.h:106
Block represents an ordered list of Operations.
Definition: Block.h:30
void recomputeOpOrder()
Recomputes the ordering of child operations within the block.
Definition: Block.cpp:124
bool empty()
Definition: Block.h:137
Operation & back()
Definition: Block.h:141
bool isOpOrderValid()
Returns true if the ordering of the child operations is valid, false otherwise.
Definition: Block.cpp:92
void dropAllDefinedValueUses()
This drops all uses of values defined in this block or in the blocks of nested regions wherever the u...
Definition: Block.cpp:82
void invalidateOpOrder()
Invalidates the current ordering of operations.
Definition: Block.cpp:95
OpListType & getOperations()
Definition: Block.h:126
Operation & front()
Definition: Block.h:142
iterator end()
Definition: Block.h:133
static OpListType Block::* getSublistAccess(Operation *)
Returns pointer to member of operation list.
Definition: Block.h:340
This class is a general helper class for creating context-global objects like types,...
Definition: Builders.h:50
MLIRContext * getContext() const
Definition: Builders.h:55
Define a fold interface to allow for dialects to control specific aspects of the folding behavior for...
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
Definition: Dialect.h:41
virtual std::optional< ParseOpHook > getParseOperationHook(StringRef opName) const
Return the hook to parse an operation registered to this dialect, if any.
Definition: Dialect.cpp:79
virtual llvm::unique_function< void(Operation *, OpAsmPrinter &printer)> getOperationPrinter(Operation *op) const
Print an operation registered to this dialect.
Definition: Dialect.cpp:84
This is a utility class for mapping one set of IR entities to another.
Definition: IRMapping.h:26
auto lookupOrDefault(T from) const
Lookup a mapped value within the map.
Definition: IRMapping.h:65
void map(Value from, Value to)
Inserts a new mapping for 'from' to 'to'.
Definition: IRMapping.h:30
This class represents a diagnostic that is inflight and set to be reported.
Definition: Diagnostics.h:308
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:63
MLIRContext * getContext() const
Return the context this location is uniqued in.
Definition: Location.h:73
NamedAttrList is array of NamedAttributes that tracks whether it is sorted and does some basic work t...
DictionaryAttr getDictionary(MLIRContext *context) const
Return a dictionary attribute for the underlying dictionary.
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
virtual void printGenericOp(Operation *op, bool printOpName=true)=0
Print the entire operation with the default generic assembly form.
RAII guard to reset the insertion point of the builder when destroyed.
Definition: Builders.h:329
This class helps build Operations.
Definition: Builders.h:202
void setInsertionPointToEnd(Block *block)
Sets the insertion point to the end of the specified block.
Definition: Builders.h:417
Block * createBlock(Region *parent, Region::iterator insertPt={}, TypeRange argTypes=std::nullopt, ArrayRef< Location > locs=std::nullopt)
Add new block with 'argTypes' arguments and set the insertion point to the end of it.
Definition: Builders.cpp:405
Operation * insert(Operation *op)
Insert the given operation at the current insertion point and return it.
Definition: Builders.cpp:396
This class represents a single result from folding an operation.
Definition: OpDefinition.h:235
This class represents an operand of an operation.
Definition: Value.h:255
Set of flags used to control the behavior of the various IR print methods (e.g.
static void printOpName(Operation *op, OpAsmPrinter &p, StringRef defaultDialect)
Print an operation name, eliding the dialect prefix if necessary.
Definition: Operation.cpp:631
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
Definition: Operation.cpp:641
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
Definition: Operation.cpp:647
InFlightDiagnostic emitWarning(const Twine &message={})
Emit a warning about this operation, reporting up to any diagnostic handlers that may be listening.
Definition: Operation.cpp:653
static ParseResult parse(OpAsmParser &parser, OperationState &result)
Parse the custom form of an operation.
Definition: Operation.cpp:611
InFlightDiagnostic emitRemark(const Twine &message={})
Emit a remark about this operation, reporting up to any diagnostic handlers that may be listening.
Definition: Operation.cpp:659
void print(raw_ostream &os, OpPrintingFlags flags=std::nullopt)
Print the operation to the given stream.
Definition: OpDefinition.h:98
This class provides the API for ops that are known to be isolated from above.
This class provides the API for ops that are known to be terminators.
Definition: OpDefinition.h:703
This class provides the API for ops that are known to have no SSA operand.
Definition: OpDefinition.h:380
This class implements the operand iterators for the Operation class.
Definition: ValueRange.h:42
type_range getTypes() const
Definition: ValueRange.cpp:26
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
bool hasTrait() const
Returns true if the operation was registered with a particular trait, e.g.
Dialect * getDialect() const
Return the dialect this operation is registered to if the dialect is loaded in the context,...
LogicalResult foldHook(Operation *op, ArrayRef< Attribute > operands, SmallVectorImpl< OpFoldResult > &results) const
This hook implements a generalized folder for this operation.
void populateDefaultAttrs(NamedAttrList &attrs) const
This hook implements the method to populate defaults attributes that are unset.
Class encompassing various options related to cloning an operation.
Definition: Operation.h:127
CloneOptions()
Default constructs an option with all flags set to false.
Definition: Operation.cpp:528
static CloneOptions all()
Returns an instance with all flags set to true.
Definition: Operation.cpp:534
CloneOptions & cloneRegions(bool enable=true)
Configures whether cloning should traverse into any of the regions of the operation.
Definition: Operation.cpp:538
CloneOptions & cloneOperands(bool enable=true)
Configures whether operation' operands should be cloned.
Definition: Operation.cpp:543
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:75
void replaceUsesOfWith(Value from, Value to)
Replace any uses of 'from' with 'to' within this operation.
Definition: Operation.cpp:193
LogicalResult fold(ArrayRef< Attribute > operands, SmallVectorImpl< OpFoldResult > &results)
Attempt to fold this operation with the specified constant operand values.
Definition: Operation.cpp:499
bool use_empty()
Returns true if this operation has no uses.
Definition: Operation.h:695
Value getOperand(unsigned idx)
Definition: Operation.h:329
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
Definition: Operation.h:592
Operation * cloneWithoutRegions()
Create a partial copy of this operation without traversing into attached regions.
Definition: Operation.cpp:556
Dialect * getDialect()
Return the dialect this operation is associated with, or nullptr if the associated dialect is not loa...
Definition: Operation.h:204
void insertOperands(unsigned index, ValueRange operands)
Insert the given operands into the operand list at the given 'index'.
Definition: Operation.cpp:222
void dropAllUses()
Drop all uses of results of this operation.
Definition: Operation.h:677
AttrClass getAttrOfType(StringAttr name)
Definition: Operation.h:437
unsigned getNumSuccessors()
Definition: Operation.h:570
bool isBeforeInBlock(Operation *other)
Given an operation 'other' that is within the same parent block, return whether the current operation...
Definition: Operation.cpp:274
void dropAllReferences()
This drops all operand uses from this operation, which is an essential step in breaking cyclic depend...
Definition: Operation.cpp:472
InFlightDiagnostic emitWarning(const Twine &message={})
Emit a warning about this operation, reporting up to any diagnostic handlers that may be listening.
Definition: Operation.cpp:246
Operation * clone(IRMapping &mapper, CloneOptions options=CloneOptions::all())
Create a deep copy of this operation, remapping any operands that use values outside of the operation...
Definition: Operation.cpp:566
bool mightHaveTrait()
Returns true if the operation might have the provided trait.
Definition: Operation.h:600
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Definition: Operation.h:386
MLIRContext * getContext()
Return the context this operation is associated with.
Definition: Operation.h:200
unsigned getNumRegions()
Returns the number of regions held by this operation.
Definition: Operation.h:537
Location getLoc()
The source location the operation was defined or derived from.
Definition: Operation.h:207
void dropAllDefinedValueUses()
Drop uses of all values defined by this operation or its nested regions.
Definition: Operation.cpp:485
unsigned getNumOperands()
Definition: Operation.h:325
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Definition: Operation.h:218
static Operation * create(Location location, OperationName name, TypeRange resultTypes, ValueRange operands, NamedAttrList &&attributes, BlockRange successors, unsigned numRegions)
Create a new Operation with the specific fields.
Definition: Operation.cpp:48
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
Definition: Operation.cpp:234
Block * getBlock()
Returns the operation block that contains this operation.
Definition: Operation.h:197
Region & getRegion(unsigned index)
Returns the region held by this operation at position 'index'.
Definition: Operation.h:550
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
Definition: Operation.h:540
void destroy()
Destroys this operation and its subclass data.
Definition: Operation.cpp:174
OperationName getName()
The name of an operation is the key identifier for it.
Definition: Operation.h:103
void remove()
Remove the operation from its parent block, but don't delete it.
Definition: Operation.cpp:435
MutableArrayRef< BlockOperand > getBlockOperands()
Definition: Operation.h:559
operand_type_range getOperandTypes()
Definition: Operation.h:376
MutableArrayRef< OpOperand > getOpOperands()
Definition: Operation.h:362
result_type_range getResultTypes()
Definition: Operation.h:407
operand_range getOperands()
Returns an iterator on the underlying Value's.
Definition: Operation.h:357
void setSuccessor(Block *block, unsigned index)
Definition: Operation.cpp:493
void moveBefore(Operation *existingOp)
Unlink this operation from its current block and insert it right before existingOp which may be in th...
Definition: Operation.cpp:443
void setOperands(ValueRange operands)
Replace the current operands of this operation with the ones provided in 'operands'.
Definition: Operation.cpp:203
user_range getUsers()
Returns a range of all users.
Definition: Operation.h:716
SuccessorRange getSuccessors()
Definition: Operation.h:567
Region * getParentRegion()
Returns the region to which the instruction belongs.
Definition: Operation.h:214
result_range getResults()
Definition: Operation.h:394
bool isProperAncestor(Operation *other)
Return true if this operation is a proper ancestor of the other operation.
Definition: Operation.cpp:185
InFlightDiagnostic emitRemark(const Twine &message={})
Emit a remark about this operation, reporting up to any diagnostic handlers that may be listening.
Definition: Operation.cpp:255
void moveAfter(Operation *existingOp)
Unlink this operation from its current block and insert it right after existingOp which may be in the...
Definition: Operation.cpp:457
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
Definition: Operation.cpp:520
void erase()
Remove this operation from its parent block and delete it.
Definition: Operation.cpp:427
unsigned getNumResults()
Return the number of results held by this operation.
Definition: Operation.h:383
This class represents success/failure for parsing-like operations that find it important to chain tog...
This class provides an abstraction over the different types of ranges over Regions.
Definition: Region.h:334
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
void cloneInto(Region *dest, IRMapping &mapper)
Clone the internal blocks from this region into dest.
Definition: Region.cpp:70
Block & back()
Definition: Region.h:64
void takeBody(Region &other)
Takes body of another region (that region will have no body after this operation completes).
Definition: Region.h:241
This class implements the result iterators for the Operation class.
Definition: ValueRange.h:231
type_range getTypes() const
Definition: ValueRange.cpp:35
Tensor types represent multi-dimensional arrays, and have two variants: RankedTensorType and Unranked...
Definition: BuiltinTypes.h:80
This class provides an efficient unique identifier for a specific C++ type.
Definition: TypeID.h:104
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 dyn_cast() const
Definition: Types.h:311
TypeID getTypeID()
Return a unique identifier for the concrete type.
Definition: Types.h:112
This class provides an abstraction over the different types of ranges over Values.
Definition: ValueRange.h:370
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:93
Type getType() const
Return the type of this value.
Definition: Value.h:122
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Definition: Value.cpp:20
This class handles the management of operation operands.
void setOperands(Operation *owner, ValueRange values)
Replace the operands contained in the storage with the ones provided in 'values'.
This class provides the implementation for an operation result whose index cannot be represented "inl...
Definition: Value.h:399
OpFoldResult foldIdempotent(Operation *op)
Definition: Operation.cpp:667
LogicalResult verifyResultsAreFloatLike(Operation *op)
Definition: Operation.cpp:995
LogicalResult verifyAtLeastNResults(Operation *op, unsigned numOperands)
Definition: Operation.cpp:826
LogicalResult verifyIsIdempotent(Operation *op)
Definition: Operation.cpp:733
LogicalResult verifyOperandsAreSignlessIntegerLike(Operation *op)
Definition: Operation.cpp:750
LogicalResult verifyNOperands(Operation *op, unsigned numOperands)
Definition: Operation.cpp:703
LogicalResult verifyNoRegionArguments(Operation *op)
Definition: Operation.cpp:1047
LogicalResult verifyResultsAreSignlessIntegerLike(Operation *op)
Definition: Operation.cpp:1004
LogicalResult verifyIsInvolution(Operation *op)
Definition: Operation.cpp:741
LogicalResult verifyOperandsAreFloatLike(Operation *op)
Definition: Operation.cpp:759
LogicalResult verifyZeroRegions(Operation *op)
Definition: Operation.cpp:781
LogicalResult verifyNSuccessors(Operation *op, unsigned numSuccessors)
Definition: Operation.cpp:965
LogicalResult verifyOperandSizeAttr(Operation *op, StringRef sizeAttrName)
Definition: Operation.cpp:1037
LogicalResult verifyAtLeastNRegions(Operation *op, unsigned numRegions)
Definition: Operation.cpp:800
LogicalResult verifyValueSizeAttr(Operation *op, StringRef attrName, StringRef valueGroupName, size_t expectedCount)
Definition: Operation.cpp:1011
LogicalResult verifyZeroResults(Operation *op)
Definition: Operation.cpp:807
LogicalResult verifySameOperandsAndResultType(Operation *op)
Definition: Operation.cpp:897
LogicalResult verifySameOperandsShape(Operation *op)
Definition: Operation.cpp:834
LogicalResult verifyAtLeastNSuccessors(Operation *op, unsigned numSuccessors)
Definition: Operation.cpp:974
LogicalResult verifyIsTerminator(Operation *op)
Definition: Operation.cpp:932
LogicalResult verifyAtLeastNOperands(Operation *op, unsigned numOperands)
Definition: Operation.cpp:712
LogicalResult verifyZeroOperands(Operation *op)
Definition: Operation.cpp:691
LogicalResult verifyElementwise(Operation *op)
Definition: Operation.cpp:1062
LogicalResult verifyOneRegion(Operation *op)
Definition: Operation.cpp:787
LogicalResult verifyOneOperand(Operation *op)
Definition: Operation.cpp:697
LogicalResult verifyIsIsolatedFromAbove(Operation *op)
Check for any values used by operations regions attached to the specified "IsIsolatedFromAbove" opera...
Definition: Operation.cpp:1105
LogicalResult verifyZeroSuccessors(Operation *op)
Definition: Operation.cpp:950
LogicalResult verifySameOperandsElementType(Operation *op)
Definition: Operation.cpp:859
LogicalResult verifyOneSuccessor(Operation *op)
Definition: Operation.cpp:958
LogicalResult verifySameOperandsAndResultElementType(Operation *op)
Definition: Operation.cpp:873
OpFoldResult foldInvolution(Operation *op)
Definition: Operation.cpp:681
LogicalResult verifyResultsAreBoolLike(Operation *op)
Definition: Operation.cpp:984
LogicalResult verifyNResults(Operation *op, unsigned numOperands)
Definition: Operation.cpp:819
LogicalResult verifyResultSizeAttr(Operation *op, StringRef sizeAttrName)
Definition: Operation.cpp:1042
LogicalResult verifyNRegions(Operation *op, unsigned numRegions)
Definition: Operation.cpp:793
LogicalResult verifyOneResult(Operation *op)
Definition: Operation.cpp:813
LogicalResult verifySameTypeOperands(Operation *op)
Definition: Operation.cpp:768
LogicalResult verifySameOperandsAndResultShape(Operation *op)
Definition: Operation.cpp:844
bool hasElementwiseMappableTraits(Operation *op)
Together, Elementwise, Scalarizable, Vectorizable, and Tensorizable provide an easy way for scalar op...
Definition: Operation.cpp:1147
LogicalResult foldCastInterfaceOp(Operation *op, ArrayRef< Attribute > attrOperands, SmallVectorImpl< OpFoldResult > &foldResults)
Attempt to fold the given cast operation.
Definition: Operation.cpp:1158
LogicalResult verifyCastInterfaceOp(Operation *op, function_ref< bool(TypeRange, TypeRange)> areCastCompatible)
Attempt to verify the given cast operation.
Definition: Operation.cpp:1175
void ensureRegionTerminator(Region &region, OpBuilder &builder, Location loc, function_ref< Operation *(OpBuilder &, Location)> buildTerminatorOp)
Insert an operation, generated by buildTerminatorOp, at the end of the region's only block if it does...
Definition: Operation.cpp:1206
This header declares functions that assit transformations in the MemRef dialect.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
InFlightDiagnostic emitWarning(Location loc)
Utility method to emit a warning message using this location.
LogicalResult verifyCompatibleShapes(TypeRange types1, TypeRange types2)
Returns success if the given two arrays have the same number of elements and each pair wise entries h...
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
Type getElementTypeOrSelf(Type type)
Return the element type or return the type itself.
InFlightDiagnostic emitRemark(Location loc)
Utility method to emit a remark message using this location.
LogicalResult verifyCompatibleShape(ArrayRef< int64_t > shape1, ArrayRef< int64_t > shape2)
Returns success if the given two shapes are compatible.
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
Definition: LogicalResult.h:72
void removeNodeFromList(Operation *op)
This is a trait method invoked when an operation is removed from a block.
Definition: Operation.cpp:401
void transferNodesFromList(ilist_traits< Operation > &otherList, op_iterator first, op_iterator last)
This is a trait method invoked when an operation is moved from one block to another.
Definition: Operation.cpp:408
void addNodeToList(Operation *op)
This is a trait method invoked when an operation is added to a block.
Definition: Operation.cpp:391
static void deleteNode(Operation *op)
Definition: Operation.cpp:379
simple_ilist< Operation >::iterator op_iterator
Definition: BlockSupport.h:228
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
This trait tags element-wise ops on vectors or tensors.
This trait tags Elementwise operatons that can be systematically scalarized.
This trait tags Elementwise operatons that can be systematically tensorized.
This trait tags Elementwise operatons that can be systematically vectorized.
This represents an operation in an abstracted form, suitable for use with the builder APIs.
SmallVector< Block *, 1 > successors
Successors of this operation and their respective operands.
SmallVector< Value, 4 > operands
SmallVector< std::unique_ptr< Region >, 1 > regions
Regions that the op will hold.
NamedAttrList attributes
MLIRContext * getContext() const
Get the context held by this operation state.
SmallVector< Type, 4 > types
Types of the results of this operation.
This class provides the implementation for an operation result whose index can be represented "inline...
Definition: Value.h:382