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