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