xref: /llvm-project/mlir/lib/IR/Operation.cpp (revision f4d758634305304c0deb49a4ed3f99180a2488ea)
15187cfcfSChris Lattner //===- Operation.cpp - Operation support code -----------------------------===//
2b0dabbd6SChris Lattner //
330857107SMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
456222a06SMehdi Amini // See https://llvm.org/LICENSE.txt for license information.
556222a06SMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b0dabbd6SChris Lattner //
756222a06SMehdi Amini //===----------------------------------------------------------------------===//
8b0dabbd6SChris Lattner 
99ffdc930SRiver Riddle #include "mlir/IR/Operation.h"
105e118f93SMehdi Amini #include "mlir/IR/Attributes.h"
115e118f93SMehdi Amini #include "mlir/IR/BuiltinAttributes.h"
1209f7a55fSRiver Riddle #include "mlir/IR/BuiltinTypes.h"
13f8f723cfSFeng Liu #include "mlir/IR/Dialect.h"
144d67b278SJeff Niu #include "mlir/IR/IRMapping.h"
15dd115e5aSMatthias Springer #include "mlir/IR/Matchers.h"
16be8069ebSChris Lattner #include "mlir/IR/OpImplementation.h"
175e118f93SMehdi Amini #include "mlir/IR/OperationSupport.h"
18c9b0540bSSmit Hinsu #include "mlir/IR/PatternMatch.h"
1918db4ce4SGeoffrey Martin-Noble #include "mlir/IR/TypeUtilities.h"
20c224bc71SMehdi Amini #include "mlir/Interfaces/FoldInterfaces.h"
215e118f93SMehdi Amini #include "llvm/ADT/SmallVector.h"
22c41b16c2SMehdi Amini #include "llvm/ADT/StringExtras.h"
2392157417SJakub Kuderski #include "llvm/Support/ErrorHandling.h"
24c6b294acSJacques Pienaar #include <numeric>
25eed9932aSKazu Hirata #include <optional>
2618db4ce4SGeoffrey Martin-Noble 
27b0dabbd6SChris Lattner using namespace mlir;
28b0dabbd6SChris Lattner 
29626e1fd9SRiver Riddle //===----------------------------------------------------------------------===//
309ffdc930SRiver Riddle // Operation
319ffdc930SRiver Riddle //===----------------------------------------------------------------------===//
329ffdc930SRiver Riddle 
335a5bba02SAlex Zinenko /// Create a new Operation from operation state.
345a5bba02SAlex Zinenko Operation *Operation::create(const OperationState &state) {
355e118f93SMehdi Amini   Operation *op =
365e118f93SMehdi Amini       create(state.location, state.name, state.types, state.operands,
37fc5cf50eSRiver Riddle              state.attributes.getDictionary(state.getContext()),
385e118f93SMehdi Amini              state.properties, state.successors, state.regions);
395e118f93SMehdi Amini   if (LLVM_UNLIKELY(state.propertiesAttr)) {
405e118f93SMehdi Amini     assert(!state.properties);
415e118f93SMehdi Amini     LogicalResult result =
425e118f93SMehdi Amini         op->setPropertiesFromAttribute(state.propertiesAttr,
435e118f93SMehdi Amini                                        /*diagnostic=*/nullptr);
445e118f93SMehdi Amini     assert(result.succeeded() && "invalid properties in op creation");
455e118f93SMehdi Amini     (void)result;
465e118f93SMehdi Amini   }
475e118f93SMehdi Amini   return op;
48f27ceb72SJacques Pienaar }
49f27ceb72SJacques Pienaar 
50f27ceb72SJacques Pienaar /// Create a new Operation with the specific fields.
51f27ceb72SJacques Pienaar Operation *Operation::create(Location location, OperationName name,
528893d081SRahul Joshi                              TypeRange resultTypes, ValueRange operands,
535e118f93SMehdi Amini                              NamedAttrList &&attributes,
545e118f93SMehdi Amini                              OpaqueProperties properties, BlockRange successors,
55fc5cf50eSRiver Riddle                              RegionRange regions) {
56f27ceb72SJacques Pienaar   unsigned numRegions = regions.size();
575e118f93SMehdi Amini   Operation *op =
585e118f93SMehdi Amini       create(location, name, resultTypes, operands, std::move(attributes),
595e118f93SMehdi Amini              properties, successors, numRegions);
605a5bba02SAlex Zinenko   for (unsigned i = 0; i < numRegions; ++i)
61f27ceb72SJacques Pienaar     if (regions[i])
62f27ceb72SJacques Pienaar       op->getRegion(i).takeBody(*regions[i]);
63af9760feSRiver Riddle   return op;
645a5bba02SAlex Zinenko }
655a5bba02SAlex Zinenko 
66f25cfd33SJeff Niu /// Create a new Operation with the specific fields.
67f25cfd33SJeff Niu Operation *Operation::create(Location location, OperationName name,
68f25cfd33SJeff Niu                              TypeRange resultTypes, ValueRange operands,
695e118f93SMehdi Amini                              NamedAttrList &&attributes,
705e118f93SMehdi Amini                              OpaqueProperties properties, BlockRange successors,
71f25cfd33SJeff Niu                              unsigned numRegions) {
72f25cfd33SJeff Niu   // Populate default attributes.
73f25cfd33SJeff Niu   name.populateDefaultAttrs(attributes);
74f25cfd33SJeff Niu 
75f25cfd33SJeff Niu   return create(location, name, resultTypes, operands,
765e118f93SMehdi Amini                 attributes.getDictionary(location.getContext()), properties,
775e118f93SMehdi Amini                 successors, numRegions);
78f25cfd33SJeff Niu }
79f25cfd33SJeff Niu 
80fc5cf50eSRiver Riddle /// Overload of create that takes an existing DictionaryAttr to avoid
819ffdc930SRiver Riddle /// unnecessarily uniquing a list of attributes.
829ffdc930SRiver Riddle Operation *Operation::create(Location location, OperationName name,
838893d081SRahul Joshi                              TypeRange resultTypes, ValueRange operands,
845e118f93SMehdi Amini                              DictionaryAttr attributes,
855e118f93SMehdi Amini                              OpaqueProperties properties, BlockRange successors,
86fc5cf50eSRiver Riddle                              unsigned numRegions) {
873dfa8614SRiver Riddle   assert(llvm::all_of(resultTypes, [](Type t) { return t; }) &&
883dfa8614SRiver Riddle          "unexpected null result type");
893dfa8614SRiver Riddle 
90fd01d862SRiver Riddle   // We only need to allocate additional memory for a subset of results.
91fd01d862SRiver Riddle   unsigned numTrailingResults = OpResult::getNumTrailing(resultTypes.size());
9248e9ef43SRiver Riddle   unsigned numInlineResults = OpResult::getNumInline(resultTypes.size());
93cb177712SRiver Riddle   unsigned numSuccessors = successors.size();
94cb177712SRiver Riddle   unsigned numOperands = operands.size();
953dfa8614SRiver Riddle   unsigned numResults = resultTypes.size();
96a3ef1b58SMehdi Amini   int opPropertiesAllocSize = llvm::alignTo<8>(name.getOpPropertyByteSize());
979ffdc930SRiver Riddle 
981956a8a7SRiver Riddle   // If the operation is known to have no operands, don't allocate an operand
991956a8a7SRiver Riddle   // storage.
100edc6c0ecSRiver Riddle   bool needsOperandStorage =
101edc6c0ecSRiver Riddle       operands.empty() ? !name.hasTrait<OpTrait::ZeroOperands>() : true;
1021956a8a7SRiver Riddle 
10347364f95SRiver Riddle   // Compute the byte size for the operation and the operand storage. This takes
10447364f95SRiver Riddle   // into account the size of the operation, its trailing objects, and its
10547364f95SRiver Riddle   // prefixed objects.
10647364f95SRiver Riddle   size_t byteSize =
1075e118f93SMehdi Amini       totalSizeToAlloc<detail::OperandStorage, detail::OpProperties,
1085e118f93SMehdi Amini                        BlockOperand, Region, OpOperand>(
1095e118f93SMehdi Amini           needsOperandStorage ? 1 : 0, opPropertiesAllocSize, numSuccessors,
1105e118f93SMehdi Amini           numRegions, numOperands);
11147364f95SRiver Riddle   size_t prefixByteSize = llvm::alignTo(
11247364f95SRiver Riddle       Operation::prefixAllocSize(numTrailingResults, numInlineResults),
1139ffdc930SRiver Riddle       alignof(Operation));
11447364f95SRiver Riddle   char *mallocMem = reinterpret_cast<char *>(malloc(byteSize + prefixByteSize));
11547364f95SRiver Riddle   void *rawMem = mallocMem + prefixByteSize;
1169ffdc930SRiver Riddle 
1179ffdc930SRiver Riddle   // Create the new Operation.
1185e118f93SMehdi Amini   Operation *op = ::new (rawMem) Operation(
1195e118f93SMehdi Amini       location, name, numResults, numSuccessors, numRegions,
1205e118f93SMehdi Amini       opPropertiesAllocSize, attributes, properties, needsOperandStorage);
1219ffdc930SRiver Riddle 
122fe7c0d90SRiver Riddle   assert((numSuccessors == 0 || op->mightHaveTrait<OpTrait::IsTerminator>()) &&
1239ffdc930SRiver Riddle          "unexpected successors in a non-terminator operation");
1249ffdc930SRiver Riddle 
12548e9ef43SRiver Riddle   // Initialize the results.
1263dfa8614SRiver Riddle   auto resultTypeIt = resultTypes.begin();
1273dfa8614SRiver Riddle   for (unsigned i = 0; i < numInlineResults; ++i, ++resultTypeIt)
1283dfa8614SRiver Riddle     new (op->getInlineOpResult(i)) detail::InlineOpResult(*resultTypeIt, i);
1293dfa8614SRiver Riddle   for (unsigned i = 0; i < numTrailingResults; ++i, ++resultTypeIt) {
1303dfa8614SRiver Riddle     new (op->getOutOfLineOpResult(i))
1313dfa8614SRiver Riddle         detail::OutOfLineOpResult(*resultTypeIt, i);
1323dfa8614SRiver Riddle   }
133fd01d862SRiver Riddle 
1349ffdc930SRiver Riddle   // Initialize the regions.
1359ffdc930SRiver Riddle   for (unsigned i = 0; i != numRegions; ++i)
1369ffdc930SRiver Riddle     new (&op->getRegion(i)) Region(op);
1379ffdc930SRiver Riddle 
138cb177712SRiver Riddle   // Initialize the operands.
139a0391134SRiver Riddle   if (needsOperandStorage) {
140a0391134SRiver Riddle     new (&op->getOperandStorage()) detail::OperandStorage(
141a0391134SRiver Riddle         op, op->getTrailingObjects<OpOperand>(), operands);
142a0391134SRiver Riddle   }
1439ffdc930SRiver Riddle 
144cb177712SRiver Riddle   // Initialize the successors.
145cb177712SRiver Riddle   auto blockOperands = op->getBlockOperands();
146cb177712SRiver Riddle   for (unsigned i = 0; i != numSuccessors; ++i)
147cb177712SRiver Riddle     new (&blockOperands[i]) BlockOperand(op, successors[i]);
1489ffdc930SRiver Riddle 
1495e118f93SMehdi Amini   // This must be done after properties are initalized.
1505e118f93SMehdi Amini   op->setAttrs(attributes);
1515e118f93SMehdi Amini 
1529ffdc930SRiver Riddle   return op;
1539ffdc930SRiver Riddle }
1549ffdc930SRiver Riddle 
1553dfa8614SRiver Riddle Operation::Operation(Location location, OperationName name, unsigned numResults,
1563dfa8614SRiver Riddle                      unsigned numSuccessors, unsigned numRegions,
1575e118f93SMehdi Amini                      int fullPropertiesStorageSize, DictionaryAttr attributes,
1585e118f93SMehdi Amini                      OpaqueProperties properties, bool hasOperandStorage)
1593dfa8614SRiver Riddle     : location(location), numResults(numResults), numSuccs(numSuccessors),
1605e118f93SMehdi Amini       numRegions(numRegions), hasOperandStorage(hasOperandStorage),
1615e118f93SMehdi Amini       propertiesStorageSize((fullPropertiesStorageSize + 7) / 8), name(name) {
162fc5cf50eSRiver Riddle   assert(attributes && "unexpected null attribute dictionary");
1635e118f93SMehdi Amini   assert(fullPropertiesStorageSize <= propertiesCapacity &&
1645e118f93SMehdi Amini          "Properties size overflow");
1650f9e6451SMehdi Amini #ifndef NDEBUG
1660f9e6451SMehdi Amini   if (!getDialect() && !getContext()->allowsUnregisteredDialects())
1670f9e6451SMehdi Amini     llvm::report_fatal_error(
1680f9e6451SMehdi Amini         name.getStringRef() +
1690f9e6451SMehdi Amini         " created with unregistered dialect. If this is intended, please call "
1700f9e6451SMehdi Amini         "allowUnregisteredDialects() on the MLIRContext, or use "
17105fb2606SUday Bondhugula         "-allow-unregistered-dialect with the MLIR tool used.");
1720f9e6451SMehdi Amini #endif
1735e118f93SMehdi Amini   if (fullPropertiesStorageSize)
1745e118f93SMehdi Amini     name.initOpProperties(getPropertiesStorage(), properties);
175fd01d862SRiver Riddle }
1769ffdc930SRiver Riddle 
1779ffdc930SRiver Riddle // Operations are deleted through the destroy() member because they are
1789ffdc930SRiver Riddle // allocated via malloc.
1799ffdc930SRiver Riddle Operation::~Operation() {
1809ffdc930SRiver Riddle   assert(block == nullptr && "operation destroyed but still in a block");
181a360a978SMehdi Amini #ifndef NDEBUG
182a360a978SMehdi Amini   if (!use_empty()) {
183a360a978SMehdi Amini     {
184a360a978SMehdi Amini       InFlightDiagnostic diag =
185a360a978SMehdi Amini           emitOpError("operation destroyed but still has uses");
186a360a978SMehdi Amini       for (Operation *user : getUsers())
187a360a978SMehdi Amini         diag.attachNote(user->getLoc()) << "- use: " << *user << "\n";
188a360a978SMehdi Amini     }
189a360a978SMehdi Amini     llvm::report_fatal_error("operation destroyed but still has uses");
190a360a978SMehdi Amini   }
191a360a978SMehdi Amini #endif
1921956a8a7SRiver Riddle   // Explicitly run the destructors for the operands.
1931956a8a7SRiver Riddle   if (hasOperandStorage)
1949ffdc930SRiver Riddle     getOperandStorage().~OperandStorage();
1959ffdc930SRiver Riddle 
1969ffdc930SRiver Riddle   // Explicitly run the destructors for the successors.
1979ffdc930SRiver Riddle   for (auto &successor : getBlockOperands())
1989ffdc930SRiver Riddle     successor.~BlockOperand();
1999ffdc930SRiver Riddle 
2009ffdc930SRiver Riddle   // Explicitly destroy the regions.
2019ffdc930SRiver Riddle   for (auto &region : getRegions())
2029ffdc930SRiver Riddle     region.~Region();
2035e118f93SMehdi Amini   if (propertiesStorageSize)
2045e118f93SMehdi Amini     name.destroyOpProperties(getPropertiesStorage());
2059ffdc930SRiver Riddle }
2069ffdc930SRiver Riddle 
2079ffdc930SRiver Riddle /// Destroy this operation or one of its subclasses.
2089ffdc930SRiver Riddle void Operation::destroy() {
20947364f95SRiver Riddle   // Operations may have additional prefixed allocation, which needs to be
21047364f95SRiver Riddle   // accounted for here when computing the address to free.
21147364f95SRiver Riddle   char *rawMem = reinterpret_cast<char *>(this) -
21247364f95SRiver Riddle                  llvm::alignTo(prefixAllocSize(), alignof(Operation));
2139ffdc930SRiver Riddle   this->~Operation();
21447364f95SRiver Riddle   free(rawMem);
2159ffdc930SRiver Riddle }
2169ffdc930SRiver Riddle 
21735df5108SRiver Riddle /// Return true if this operation is a proper ancestor of the `other`
21835df5108SRiver Riddle /// operation.
21935df5108SRiver Riddle bool Operation::isProperAncestor(Operation *other) {
22035df5108SRiver Riddle   while ((other = other->getParentOp()))
22135df5108SRiver Riddle     if (this == other)
22235df5108SRiver Riddle       return true;
22335df5108SRiver Riddle   return false;
22435df5108SRiver Riddle }
22535df5108SRiver Riddle 
2261e2d2f5dSRiver Riddle /// Replace any uses of 'from' with 'to' within this operation.
227e62a6956SRiver Riddle void Operation::replaceUsesOfWith(Value from, Value to) {
2281e2d2f5dSRiver Riddle   if (from == to)
2291e2d2f5dSRiver Riddle     return;
2301e2d2f5dSRiver Riddle   for (auto &operand : getOpOperands())
2311e2d2f5dSRiver Riddle     if (operand.get() == from)
2321e2d2f5dSRiver Riddle       operand.set(to);
2331e2d2f5dSRiver Riddle }
2341e2d2f5dSRiver Riddle 
235d6ee6a03SRiver Riddle /// Replace the current operands of this operation with the ones provided in
2364dfd1b5fSRiver Riddle /// 'operands'.
237d6ee6a03SRiver Riddle void Operation::setOperands(ValueRange operands) {
2381956a8a7SRiver Riddle   if (LLVM_LIKELY(hasOperandStorage))
2391956a8a7SRiver Riddle     return getOperandStorage().setOperands(this, operands);
2401956a8a7SRiver Riddle   assert(operands.empty() && "setting operands without an operand storage");
241d6ee6a03SRiver Riddle }
242d6ee6a03SRiver Riddle 
243108abd2fSRiver Riddle /// Replace the operands beginning at 'start' and ending at 'start' + 'length'
244108abd2fSRiver Riddle /// with the ones provided in 'operands'. 'operands' may be smaller or larger
245108abd2fSRiver Riddle /// than the range pointed to by 'start'+'length'.
246108abd2fSRiver Riddle void Operation::setOperands(unsigned start, unsigned length,
247108abd2fSRiver Riddle                             ValueRange operands) {
248108abd2fSRiver Riddle   assert((start + length) <= getNumOperands() &&
249108abd2fSRiver Riddle          "invalid operand range specified");
250108abd2fSRiver Riddle   if (LLVM_LIKELY(hasOperandStorage))
251108abd2fSRiver Riddle     return getOperandStorage().setOperands(this, start, length, operands);
252108abd2fSRiver Riddle   assert(operands.empty() && "setting operands without an operand storage");
253108abd2fSRiver Riddle }
254108abd2fSRiver Riddle 
255108abd2fSRiver Riddle /// Insert the given operands into the operand list at the given 'index'.
256108abd2fSRiver Riddle void Operation::insertOperands(unsigned index, ValueRange operands) {
257108abd2fSRiver Riddle   if (LLVM_LIKELY(hasOperandStorage))
258108abd2fSRiver Riddle     return setOperands(index, /*length=*/0, operands);
259108abd2fSRiver Riddle   assert(operands.empty() && "inserting operands without an operand storage");
260108abd2fSRiver Riddle }
261108abd2fSRiver Riddle 
2629ffdc930SRiver Riddle //===----------------------------------------------------------------------===//
263626e1fd9SRiver Riddle // Diagnostics
2649ffdc930SRiver Riddle //===----------------------------------------------------------------------===//
2659ffdc930SRiver Riddle 
266777e7b4fSRiver Riddle /// Emit an error about fatal conditions with this operation, reporting up to
267777e7b4fSRiver Riddle /// any diagnostic handlers that may be listening.
268777e7b4fSRiver Riddle InFlightDiagnostic Operation::emitError(const Twine &message) {
269626e1fd9SRiver Riddle   InFlightDiagnostic diag = mlir::emitError(getLoc(), message);
27079afdfabSRiver Riddle   if (getContext()->shouldPrintOpOnDiagnostic()) {
271a77cd55dSRiver Riddle     diag.attachNote(getLoc())
272a77cd55dSRiver Riddle         .append("see current operation: ")
273a77cd55dSRiver Riddle         .appendOp(*this, OpPrintingFlags().printGenericOpForm());
274626e1fd9SRiver Riddle   }
275626e1fd9SRiver Riddle   return diag;
276b14c4b4cSRiver Riddle }
277b14c4b4cSRiver Riddle 
2789ffdc930SRiver Riddle /// Emit a warning about this operation, reporting up to any diagnostic
2799ffdc930SRiver Riddle /// handlers that may be listening.
280ff6e7cf5SRiver Riddle InFlightDiagnostic Operation::emitWarning(const Twine &message) {
281626e1fd9SRiver Riddle   InFlightDiagnostic diag = mlir::emitWarning(getLoc(), message);
28279afdfabSRiver Riddle   if (getContext()->shouldPrintOpOnDiagnostic())
283626e1fd9SRiver Riddle     diag.attachNote(getLoc()) << "see current operation: " << *this;
284626e1fd9SRiver Riddle   return diag;
2859ffdc930SRiver Riddle }
2869ffdc930SRiver Riddle 
287777e7b4fSRiver Riddle /// Emit a remark about this operation, reporting up to any diagnostic
288777e7b4fSRiver Riddle /// handlers that may be listening.
289777e7b4fSRiver Riddle InFlightDiagnostic Operation::emitRemark(const Twine &message) {
290626e1fd9SRiver Riddle   InFlightDiagnostic diag = mlir::emitRemark(getLoc(), message);
29179afdfabSRiver Riddle   if (getContext()->shouldPrintOpOnDiagnostic())
292626e1fd9SRiver Riddle     diag.attachNote(getLoc()) << "see current operation: " << *this;
293626e1fd9SRiver Riddle   return diag;
2949ffdc930SRiver Riddle }
2959ffdc930SRiver Riddle 
2965e118f93SMehdi Amini DictionaryAttr Operation::getAttrDictionary() {
2975e118f93SMehdi Amini   if (getPropertiesStorageSize()) {
2985e118f93SMehdi Amini     NamedAttrList attrsList = attrs;
2995e118f93SMehdi Amini     getName().populateInherentAttrs(this, attrsList);
3005e118f93SMehdi Amini     return attrsList.getDictionary(getContext());
3015e118f93SMehdi Amini   }
3025e118f93SMehdi Amini   return attrs;
3035e118f93SMehdi Amini }
3045e118f93SMehdi Amini 
3055e118f93SMehdi Amini void Operation::setAttrs(DictionaryAttr newAttrs) {
3065e118f93SMehdi Amini   assert(newAttrs && "expected valid attribute dictionary");
3075e118f93SMehdi Amini   if (getPropertiesStorageSize()) {
30831511900SMehdi Amini     // We're spliting the providing DictionaryAttr by removing the inherentAttr
30931511900SMehdi Amini     // which will be stored in the properties.
31031511900SMehdi Amini     SmallVector<NamedAttribute> discardableAttrs;
31131511900SMehdi Amini     discardableAttrs.reserve(newAttrs.size());
31231511900SMehdi Amini     for (NamedAttribute attr : newAttrs) {
3130a0aff2dSMikhail Goncharov       if (getInherentAttr(attr.getName()))
31431511900SMehdi Amini         setInherentAttr(attr.getName(), attr.getValue());
31531511900SMehdi Amini       else
31631511900SMehdi Amini         discardableAttrs.push_back(attr);
31731511900SMehdi Amini     }
31831511900SMehdi Amini     if (discardableAttrs.size() != newAttrs.size())
31931511900SMehdi Amini       newAttrs = DictionaryAttr::get(getContext(), discardableAttrs);
3205e118f93SMehdi Amini   }
3215e118f93SMehdi Amini   attrs = newAttrs;
3225e118f93SMehdi Amini }
3235e118f93SMehdi Amini void Operation::setAttrs(ArrayRef<NamedAttribute> newAttrs) {
3245e118f93SMehdi Amini   if (getPropertiesStorageSize()) {
32531511900SMehdi Amini     // We're spliting the providing array of attributes by removing the inherentAttr
32631511900SMehdi Amini     // which will be stored in the properties.
32731511900SMehdi Amini     SmallVector<NamedAttribute> discardableAttrs;
32831511900SMehdi Amini     discardableAttrs.reserve(newAttrs.size());
32931511900SMehdi Amini     for (NamedAttribute attr : newAttrs) {
3300a0aff2dSMikhail Goncharov       if (getInherentAttr(attr.getName()))
33131511900SMehdi Amini         setInherentAttr(attr.getName(), attr.getValue());
33231511900SMehdi Amini       else
33331511900SMehdi Amini         discardableAttrs.push_back(attr);
33431511900SMehdi Amini     }
33531511900SMehdi Amini     attrs = DictionaryAttr::get(getContext(), discardableAttrs);
3365e118f93SMehdi Amini     return;
3375e118f93SMehdi Amini   }
3385e118f93SMehdi Amini   attrs = DictionaryAttr::get(getContext(), newAttrs);
3395e118f93SMehdi Amini }
3405e118f93SMehdi Amini 
3415e118f93SMehdi Amini std::optional<Attribute> Operation::getInherentAttr(StringRef name) {
3425e118f93SMehdi Amini   return getName().getInherentAttr(this, name);
3435e118f93SMehdi Amini }
3445e118f93SMehdi Amini 
3455e118f93SMehdi Amini void Operation::setInherentAttr(StringAttr name, Attribute value) {
3465e118f93SMehdi Amini   getName().setInherentAttr(this, name, value);
3475e118f93SMehdi Amini }
3485e118f93SMehdi Amini 
3495e118f93SMehdi Amini Attribute Operation::getPropertiesAsAttribute() {
350eed9932aSKazu Hirata   std::optional<RegisteredOperationName> info = getRegisteredInfo();
3515e118f93SMehdi Amini   if (LLVM_UNLIKELY(!info))
3525e118f93SMehdi Amini     return *getPropertiesStorage().as<Attribute *>();
3535e118f93SMehdi Amini   return info->getOpPropertiesAsAttribute(this);
3545e118f93SMehdi Amini }
3558c2bff1aSMehdi Amini LogicalResult Operation::setPropertiesFromAttribute(
356c50617daSMehdi Amini     Attribute attr, function_ref<InFlightDiagnostic()> emitError) {
357eed9932aSKazu Hirata   std::optional<RegisteredOperationName> info = getRegisteredInfo();
3585e118f93SMehdi Amini   if (LLVM_UNLIKELY(!info)) {
3595e118f93SMehdi Amini     *getPropertiesStorage().as<Attribute *>() = attr;
3605e118f93SMehdi Amini     return success();
3615e118f93SMehdi Amini   }
362863e8123SJacques Pienaar   return info->setOpPropertiesFromAttribute(
363c50617daSMehdi Amini       this->getName(), this->getPropertiesStorage(), attr, emitError);
3645e118f93SMehdi Amini }
3655e118f93SMehdi Amini 
3665e118f93SMehdi Amini void Operation::copyProperties(OpaqueProperties rhs) {
3675e118f93SMehdi Amini   name.copyOpProperties(getPropertiesStorage(), rhs);
3685e118f93SMehdi Amini }
3695e118f93SMehdi Amini 
3705e118f93SMehdi Amini llvm::hash_code Operation::hashProperties() {
3715e118f93SMehdi Amini   return name.hashOpProperties(getPropertiesStorage());
3725e118f93SMehdi Amini }
3735e118f93SMehdi Amini 
374626e1fd9SRiver Riddle //===----------------------------------------------------------------------===//
375d9da8b64SRiver Riddle // Operation Ordering
376626e1fd9SRiver Riddle //===----------------------------------------------------------------------===//
377626e1fd9SRiver Riddle 
378d9da8b64SRiver Riddle constexpr unsigned Operation::kInvalidOrderIdx;
379d9da8b64SRiver Riddle constexpr unsigned Operation::kOrderStride;
380d9da8b64SRiver Riddle 
3819ffdc930SRiver Riddle /// Given an operation 'other' that is within the same parent block, return
3829ffdc930SRiver Riddle /// whether the current operation is before 'other' in the operation list
3839ffdc930SRiver Riddle /// of the parent block.
3849ffdc930SRiver Riddle /// Note: This function has an average complexity of O(1), but worst case may
3859ffdc930SRiver Riddle /// take O(N) where N is the number of operations within the parent block.
3869ffdc930SRiver Riddle bool Operation::isBeforeInBlock(Operation *other) {
3879ffdc930SRiver Riddle   assert(block && "Operations without parent blocks have no order.");
3889ffdc930SRiver Riddle   assert(other && other->block == block &&
3899ffdc930SRiver Riddle          "Expected other operation to have the same parent block.");
390d9da8b64SRiver Riddle   // If the order of the block is already invalid, directly recompute the
391d9da8b64SRiver Riddle   // parent.
392d9da8b64SRiver Riddle   if (!block->isOpOrderValid()) {
393f6188b5bSSean Silva     block->recomputeOpOrder();
394d9da8b64SRiver Riddle   } else {
395d9da8b64SRiver Riddle     // Update the order either operation if necessary.
396d9da8b64SRiver Riddle     updateOrderIfNecessary();
397d9da8b64SRiver Riddle     other->updateOrderIfNecessary();
398d9da8b64SRiver Riddle   }
399d9da8b64SRiver Riddle 
4009ffdc930SRiver Riddle   return orderIndex < other->orderIndex;
4019ffdc930SRiver Riddle }
4029ffdc930SRiver Riddle 
403d9da8b64SRiver Riddle /// Update the order index of this operation of this operation if necessary,
404d9da8b64SRiver Riddle /// potentially recomputing the order of the parent block.
405d9da8b64SRiver Riddle void Operation::updateOrderIfNecessary() {
406d9da8b64SRiver Riddle   assert(block && "expected valid parent");
407d9da8b64SRiver Riddle 
408d9da8b64SRiver Riddle   // If the order is valid for this operation there is nothing to do.
409041b0a81Swang-y-z   if (hasValidOrder() || llvm::hasSingleElement(*block))
410d9da8b64SRiver Riddle     return;
411d9da8b64SRiver Riddle   Operation *blockFront = &block->front();
412d9da8b64SRiver Riddle   Operation *blockBack = &block->back();
413d9da8b64SRiver Riddle 
414d9da8b64SRiver Riddle   // This method is expected to only be invoked on blocks with more than one
415d9da8b64SRiver Riddle   // operation.
416d9da8b64SRiver Riddle   assert(blockFront != blockBack && "expected more than one operation");
417d9da8b64SRiver Riddle 
418d9da8b64SRiver Riddle   // If the operation is at the end of the block.
419d9da8b64SRiver Riddle   if (this == blockBack) {
420d9da8b64SRiver Riddle     Operation *prevNode = getPrevNode();
421d9da8b64SRiver Riddle     if (!prevNode->hasValidOrder())
422d9da8b64SRiver Riddle       return block->recomputeOpOrder();
423d9da8b64SRiver Riddle 
424d9da8b64SRiver Riddle     // Add the stride to the previous operation.
425d9da8b64SRiver Riddle     orderIndex = prevNode->orderIndex + kOrderStride;
426d9da8b64SRiver Riddle     return;
427d9da8b64SRiver Riddle   }
428d9da8b64SRiver Riddle 
429d9da8b64SRiver Riddle   // If this is the first operation try to use the next operation to compute the
430d9da8b64SRiver Riddle   // ordering.
431d9da8b64SRiver Riddle   if (this == blockFront) {
432d9da8b64SRiver Riddle     Operation *nextNode = getNextNode();
433d9da8b64SRiver Riddle     if (!nextNode->hasValidOrder())
434d9da8b64SRiver Riddle       return block->recomputeOpOrder();
435d9da8b64SRiver Riddle     // There is no order to give this operation.
436d9da8b64SRiver Riddle     if (nextNode->orderIndex == 0)
437d9da8b64SRiver Riddle       return block->recomputeOpOrder();
438d9da8b64SRiver Riddle 
439d9da8b64SRiver Riddle     // If we can't use the stride, just take the middle value left. This is safe
440d9da8b64SRiver Riddle     // because we know there is at least one valid index to assign to.
441d9da8b64SRiver Riddle     if (nextNode->orderIndex <= kOrderStride)
442d9da8b64SRiver Riddle       orderIndex = (nextNode->orderIndex / 2);
443d9da8b64SRiver Riddle     else
444d9da8b64SRiver Riddle       orderIndex = kOrderStride;
445d9da8b64SRiver Riddle     return;
446d9da8b64SRiver Riddle   }
447d9da8b64SRiver Riddle 
448d9da8b64SRiver Riddle   // Otherwise, this operation is between two others. Place this operation in
449d9da8b64SRiver Riddle   // the middle of the previous and next if possible.
450d9da8b64SRiver Riddle   Operation *prevNode = getPrevNode(), *nextNode = getNextNode();
451d9da8b64SRiver Riddle   if (!prevNode->hasValidOrder() || !nextNode->hasValidOrder())
452d9da8b64SRiver Riddle     return block->recomputeOpOrder();
453d9da8b64SRiver Riddle   unsigned prevOrder = prevNode->orderIndex, nextOrder = nextNode->orderIndex;
454d9da8b64SRiver Riddle 
455d9da8b64SRiver Riddle   // Check to see if there is a valid order between the two.
456d9da8b64SRiver Riddle   if (prevOrder + 1 == nextOrder)
457d9da8b64SRiver Riddle     return block->recomputeOpOrder();
4588bdbe295SJames Molloy   orderIndex = prevOrder + ((nextOrder - prevOrder) / 2);
459d9da8b64SRiver Riddle }
460d9da8b64SRiver Riddle 
4619ffdc930SRiver Riddle //===----------------------------------------------------------------------===//
4629ffdc930SRiver Riddle // ilist_traits for Operation
4639ffdc930SRiver Riddle //===----------------------------------------------------------------------===//
4649ffdc930SRiver Riddle 
4659ffdc930SRiver Riddle auto llvm::ilist_detail::SpecificNodeAccess<
4669ffdc930SRiver Riddle     typename llvm::ilist_detail::compute_node_options<
46702b6fb21SMehdi Amini         ::mlir::Operation>::type>::getNodePtr(pointer n) -> node_type * {
46802b6fb21SMehdi Amini   return NodeAccess::getNodePtr<OptionsT>(n);
4699ffdc930SRiver Riddle }
4709ffdc930SRiver Riddle 
4719ffdc930SRiver Riddle auto llvm::ilist_detail::SpecificNodeAccess<
4729ffdc930SRiver Riddle     typename llvm::ilist_detail::compute_node_options<
47302b6fb21SMehdi Amini         ::mlir::Operation>::type>::getNodePtr(const_pointer n)
4749ffdc930SRiver Riddle     -> const node_type * {
47502b6fb21SMehdi Amini   return NodeAccess::getNodePtr<OptionsT>(n);
4769ffdc930SRiver Riddle }
4779ffdc930SRiver Riddle 
4789ffdc930SRiver Riddle auto llvm::ilist_detail::SpecificNodeAccess<
4799ffdc930SRiver Riddle     typename llvm::ilist_detail::compute_node_options<
48002b6fb21SMehdi Amini         ::mlir::Operation>::type>::getValuePtr(node_type *n) -> pointer {
48102b6fb21SMehdi Amini   return NodeAccess::getValuePtr<OptionsT>(n);
4829ffdc930SRiver Riddle }
4839ffdc930SRiver Riddle 
4849ffdc930SRiver Riddle auto llvm::ilist_detail::SpecificNodeAccess<
4859ffdc930SRiver Riddle     typename llvm::ilist_detail::compute_node_options<
48602b6fb21SMehdi Amini         ::mlir::Operation>::type>::getValuePtr(const node_type *n)
4879ffdc930SRiver Riddle     -> const_pointer {
48802b6fb21SMehdi Amini   return NodeAccess::getValuePtr<OptionsT>(n);
4899ffdc930SRiver Riddle }
4909ffdc930SRiver Riddle 
4919ffdc930SRiver Riddle void llvm::ilist_traits<::mlir::Operation>::deleteNode(Operation *op) {
4929ffdc930SRiver Riddle   op->destroy();
4939ffdc930SRiver Riddle }
4949ffdc930SRiver Riddle 
4959ffdc930SRiver Riddle Block *llvm::ilist_traits<::mlir::Operation>::getContainingBlock() {
49602b6fb21SMehdi Amini   size_t offset(size_t(&((Block *)nullptr->*Block::getSublistAccess(nullptr))));
49702b6fb21SMehdi Amini   iplist<Operation> *anchor(static_cast<iplist<Operation> *>(this));
49802b6fb21SMehdi Amini   return reinterpret_cast<Block *>(reinterpret_cast<char *>(anchor) - offset);
4999ffdc930SRiver Riddle }
5009ffdc930SRiver Riddle 
5015aacce3dSKazuaki Ishizaki /// This is a trait method invoked when an operation is added to a block.  We
5029ffdc930SRiver Riddle /// keep the block pointer up to date.
5039ffdc930SRiver Riddle void llvm::ilist_traits<::mlir::Operation>::addNodeToList(Operation *op) {
5045aacce3dSKazuaki Ishizaki   assert(!op->getBlock() && "already in an operation block!");
5059ffdc930SRiver Riddle   op->block = getContainingBlock();
5065b09ffe6SMehdi Amini 
507d9da8b64SRiver Riddle   // Invalidate the order on the operation.
508d9da8b64SRiver Riddle   op->orderIndex = Operation::kInvalidOrderIdx;
5099ffdc930SRiver Riddle }
5109ffdc930SRiver Riddle 
5115aacce3dSKazuaki Ishizaki /// This is a trait method invoked when an operation is removed from a block.
5129ffdc930SRiver Riddle /// We keep the block pointer up to date.
5139ffdc930SRiver Riddle void llvm::ilist_traits<::mlir::Operation>::removeNodeFromList(Operation *op) {
5145aacce3dSKazuaki Ishizaki   assert(op->block && "not already in an operation block!");
5159ffdc930SRiver Riddle   op->block = nullptr;
5169ffdc930SRiver Riddle }
5179ffdc930SRiver Riddle 
5185aacce3dSKazuaki Ishizaki /// This is a trait method invoked when an operation is moved from one block
5199ffdc930SRiver Riddle /// to another.  We keep the block pointer up to date.
5209ffdc930SRiver Riddle void llvm::ilist_traits<::mlir::Operation>::transferNodesFromList(
521f9d91531SRiver Riddle     ilist_traits<Operation> &otherList, op_iterator first, op_iterator last) {
5229ffdc930SRiver Riddle   Block *curParent = getContainingBlock();
5239ffdc930SRiver Riddle 
5249ffdc930SRiver Riddle   // Invalidate the ordering of the parent block.
525f6188b5bSSean Silva   curParent->invalidateOpOrder();
5269ffdc930SRiver Riddle 
5279ffdc930SRiver Riddle   // If we are transferring operations within the same block, the block
5289ffdc930SRiver Riddle   // pointer doesn't need to be updated.
5299ffdc930SRiver Riddle   if (curParent == otherList.getContainingBlock())
5309ffdc930SRiver Riddle     return;
5319ffdc930SRiver Riddle 
5329ffdc930SRiver Riddle   // Update the 'block' member of each operation.
5339ffdc930SRiver Riddle   for (; first != last; ++first)
5349ffdc930SRiver Riddle     first->block = curParent;
5359ffdc930SRiver Riddle }
5369ffdc930SRiver Riddle 
5379ffdc930SRiver Riddle /// Remove this operation (and its descendants) from its Block and delete
5389ffdc930SRiver Riddle /// all of them.
5399ffdc930SRiver Riddle void Operation::erase() {
540e7d594bbSRiver Riddle   if (auto *parent = getBlock())
541e7d594bbSRiver Riddle     parent->getOperations().erase(this);
542e7d594bbSRiver Riddle   else
543e7d594bbSRiver Riddle     destroy();
5449ffdc930SRiver Riddle }
5459ffdc930SRiver Riddle 
546abfd1a8bSRiver Riddle /// Remove the operation from its parent block, but don't delete it.
547abfd1a8bSRiver Riddle void Operation::remove() {
548abfd1a8bSRiver Riddle   if (Block *parent = getBlock())
549abfd1a8bSRiver Riddle     parent->getOperations().remove(this);
550abfd1a8bSRiver Riddle }
551abfd1a8bSRiver Riddle 
5529ffdc930SRiver Riddle /// Unlink this operation from its current block and insert it right before
553f6188b5bSSean Silva /// `existingOp` which may be in the same or another block in the same
5549ffdc930SRiver Riddle /// function.
555f6188b5bSSean Silva void Operation::moveBefore(Operation *existingOp) {
556f6188b5bSSean Silva   moveBefore(existingOp->getBlock(), existingOp->getIterator());
5579ffdc930SRiver Riddle }
5589ffdc930SRiver Riddle 
5599c085406SRiver Riddle /// Unlink this operation from its current basic block and insert it right
5609c085406SRiver Riddle /// before `iterator` in the specified basic block.
5619ffdc930SRiver Riddle void Operation::moveBefore(Block *block,
5629ffdc930SRiver Riddle                            llvm::iplist<Operation>::iterator iterator) {
563f9d91531SRiver Riddle   block->getOperations().splice(iterator, getBlock()->getOperations(),
5649ffdc930SRiver Riddle                                 getIterator());
5659ffdc930SRiver Riddle }
5669ffdc930SRiver Riddle 
5672280cb88SGeoffrey Martin-Noble /// Unlink this operation from its current block and insert it right after
5682280cb88SGeoffrey Martin-Noble /// `existingOp` which may be in the same or another block in the same function.
5692280cb88SGeoffrey Martin-Noble void Operation::moveAfter(Operation *existingOp) {
5702280cb88SGeoffrey Martin-Noble   moveAfter(existingOp->getBlock(), existingOp->getIterator());
5712280cb88SGeoffrey Martin-Noble }
5722280cb88SGeoffrey Martin-Noble 
5732280cb88SGeoffrey Martin-Noble /// Unlink this operation from its current block and insert it right after
5742280cb88SGeoffrey Martin-Noble /// `iterator` in the specified block.
5752280cb88SGeoffrey Martin-Noble void Operation::moveAfter(Block *block,
5762280cb88SGeoffrey Martin-Noble                           llvm::iplist<Operation>::iterator iterator) {
5772280cb88SGeoffrey Martin-Noble   assert(iterator != block->end() && "cannot move after end of block");
57824685aaeSAlex Zinenko   moveBefore(block, std::next(iterator));
5792280cb88SGeoffrey Martin-Noble }
5802280cb88SGeoffrey Martin-Noble 
5819ffdc930SRiver Riddle /// This drops all operand uses from this operation, which is an essential
5829ffdc930SRiver Riddle /// step in breaking cyclic dependences between references when they are to
5839ffdc930SRiver Riddle /// be deleted.
5849ffdc930SRiver Riddle void Operation::dropAllReferences() {
585213b8d4dSRiver Riddle   for (auto &op : getOpOperands())
5869ffdc930SRiver Riddle     op.drop();
5879ffdc930SRiver Riddle 
5889ffdc930SRiver Riddle   for (auto &region : getRegions())
5894dfe6d45SAlex Zinenko     region.dropAllReferences();
5909ffdc930SRiver Riddle 
5919ffdc930SRiver Riddle   for (auto &dest : getBlockOperands())
5929ffdc930SRiver Riddle     dest.drop();
5939ffdc930SRiver Riddle }
5949ffdc930SRiver Riddle 
5959ffdc930SRiver Riddle /// This drops all uses of any values defined by this operation or its nested
5969ffdc930SRiver Riddle /// regions, wherever they are located.
5979ffdc930SRiver Riddle void Operation::dropAllDefinedValueUses() {
5980d6ebb4fSRiver Riddle   dropAllUses();
5999ffdc930SRiver Riddle 
6009ffdc930SRiver Riddle   for (auto &region : getRegions())
6019ffdc930SRiver Riddle     for (auto &block : region)
6029ffdc930SRiver Riddle       block.dropAllDefinedValueUses();
6039ffdc930SRiver Riddle }
6049ffdc930SRiver Riddle 
6059ffdc930SRiver Riddle void Operation::setSuccessor(Block *block, unsigned index) {
6069ffdc930SRiver Riddle   assert(index < getNumSuccessors());
6079ffdc930SRiver Riddle   getBlockOperands()[index].set(block);
6089ffdc930SRiver Riddle }
6099ffdc930SRiver Riddle 
610f10302e3SMatthias Springer #ifndef NDEBUG
611f10302e3SMatthias Springer /// Assert that the folded results (in case of values) have the same type as
612f10302e3SMatthias Springer /// the results of the given op.
613f10302e3SMatthias Springer static void checkFoldResultTypes(Operation *op,
614f10302e3SMatthias Springer                                  SmallVectorImpl<OpFoldResult> &results) {
61592157417SJakub Kuderski   if (results.empty())
61692157417SJakub Kuderski     return;
61792157417SJakub Kuderski 
61892157417SJakub Kuderski   for (auto [ofr, opResult] : llvm::zip_equal(results, op->getResults())) {
61992157417SJakub Kuderski     if (auto value = dyn_cast<Value>(ofr)) {
62092157417SJakub Kuderski       if (value.getType() != opResult.getType()) {
62192157417SJakub Kuderski         op->emitOpError() << "folder produced a value of incorrect type: "
6224c77cc63SLuke Boyer                           << value.getType()
6234c77cc63SLuke Boyer                           << ", expected: " << opResult.getType();
62492157417SJakub Kuderski         assert(false && "incorrect fold result type");
62592157417SJakub Kuderski       }
62692157417SJakub Kuderski     }
62792157417SJakub Kuderski   }
628f10302e3SMatthias Springer }
629f10302e3SMatthias Springer #endif // NDEBUG
630f10302e3SMatthias Springer 
6311982afb1SRiver Riddle /// Attempt to fold this operation using the Op's registered foldHook.
6321982afb1SRiver Riddle LogicalResult Operation::fold(ArrayRef<Attribute> operands,
6331982afb1SRiver Riddle                               SmallVectorImpl<OpFoldResult> &results) {
6349ffdc930SRiver Riddle   // If we have a registered operation definition matching this one, use it to
6359ffdc930SRiver Riddle   // try to constant fold the operation.
636f10302e3SMatthias Springer   if (succeeded(name.foldHook(this, operands, results))) {
637f10302e3SMatthias Springer #ifndef NDEBUG
638f10302e3SMatthias Springer     checkFoldResultTypes(this, results);
639f10302e3SMatthias Springer #endif // NDEBUG
6409ffdc930SRiver Riddle     return success();
641f10302e3SMatthias Springer   }
6429ffdc930SRiver Riddle 
6439ffdc930SRiver Riddle   // Otherwise, fall back on the dialect hook to handle it.
64442c19e82SRiver Riddle   Dialect *dialect = getDialect();
64542c19e82SRiver Riddle   if (!dialect)
6469ffdc930SRiver Riddle     return failure();
6479ffdc930SRiver Riddle 
64858e7bf78SRiver Riddle   auto *interface = dyn_cast<DialectFoldInterface>(dialect);
649c224bc71SMehdi Amini   if (!interface)
6501982afb1SRiver Riddle     return failure();
651c224bc71SMehdi Amini 
652f10302e3SMatthias Springer   LogicalResult status = interface->fold(this, operands, results);
653f10302e3SMatthias Springer #ifndef NDEBUG
654f10302e3SMatthias Springer   if (succeeded(status))
655f10302e3SMatthias Springer     checkFoldResultTypes(this, results);
656f10302e3SMatthias Springer #endif // NDEBUG
657f10302e3SMatthias Springer   return status;
6589ffdc930SRiver Riddle }
6599ffdc930SRiver Riddle 
66021379151SMatthias Springer LogicalResult Operation::fold(SmallVectorImpl<OpFoldResult> &results) {
66121379151SMatthias Springer   // Check if any operands are constants.
66221379151SMatthias Springer   SmallVector<Attribute> constants;
66321379151SMatthias Springer   constants.assign(getNumOperands(), Attribute());
66421379151SMatthias Springer   for (unsigned i = 0, e = getNumOperands(); i != e; ++i)
66521379151SMatthias Springer     matchPattern(getOperand(i), m_Constant(&constants[i]));
66621379151SMatthias Springer   return fold(constants, results);
66721379151SMatthias Springer }
66821379151SMatthias Springer 
6699ffdc930SRiver Riddle /// Emit an error with the op name prefixed, like "'dim' op " which is
6709ffdc930SRiver Riddle /// convenient for verifiers.
671ff6e7cf5SRiver Riddle InFlightDiagnostic Operation::emitOpError(const Twine &message) {
672039800bfSRiver Riddle   return emitError() << "'" << getName() << "' op " << message;
6739ffdc930SRiver Riddle }
6749ffdc930SRiver Riddle 
6759ffdc930SRiver Riddle //===----------------------------------------------------------------------===//
6769ffdc930SRiver Riddle // Operation Cloning
6779ffdc930SRiver Riddle //===----------------------------------------------------------------------===//
6789ffdc930SRiver Riddle 
679a41aaf16SMarkus Böck Operation::CloneOptions::CloneOptions()
680a41aaf16SMarkus Böck     : cloneRegionsFlag(false), cloneOperandsFlag(false) {}
681a41aaf16SMarkus Böck 
682a41aaf16SMarkus Böck Operation::CloneOptions::CloneOptions(bool cloneRegions, bool cloneOperands)
683a41aaf16SMarkus Böck     : cloneRegionsFlag(cloneRegions), cloneOperandsFlag(cloneOperands) {}
684a41aaf16SMarkus Böck 
685a41aaf16SMarkus Böck Operation::CloneOptions Operation::CloneOptions::all() {
686a41aaf16SMarkus Böck   return CloneOptions().cloneRegions().cloneOperands();
687a41aaf16SMarkus Böck }
688a41aaf16SMarkus Böck 
689a41aaf16SMarkus Böck Operation::CloneOptions &Operation::CloneOptions::cloneRegions(bool enable) {
690a41aaf16SMarkus Böck   cloneRegionsFlag = enable;
691a41aaf16SMarkus Böck   return *this;
692a41aaf16SMarkus Böck }
693a41aaf16SMarkus Böck 
694a41aaf16SMarkus Böck Operation::CloneOptions &Operation::CloneOptions::cloneOperands(bool enable) {
695a41aaf16SMarkus Böck   cloneOperandsFlag = enable;
696a41aaf16SMarkus Böck   return *this;
697a41aaf16SMarkus Böck }
698a41aaf16SMarkus Böck 
6993173a63fSAlex Zinenko /// Create a deep copy of this operation but keep the operation regions empty.
7003173a63fSAlex Zinenko /// Operands are remapped using `mapper` (if present), and `mapper` is updated
7019a8bb4bcSWilliam S. Moses /// to contain the results. The `mapResults` flag specifies whether the results
7029a8bb4bcSWilliam S. Moses /// of the cloned operation should be added to the map.
7034d67b278SJeff Niu Operation *Operation::cloneWithoutRegions(IRMapping &mapper) {
704a41aaf16SMarkus Böck   return clone(mapper, CloneOptions::all().cloneRegions(false));
7053173a63fSAlex Zinenko }
7063173a63fSAlex Zinenko 
707929466b5SRiver Riddle Operation *Operation::cloneWithoutRegions() {
7084d67b278SJeff Niu   IRMapping mapper;
709929466b5SRiver Riddle   return cloneWithoutRegions(mapper);
7103173a63fSAlex Zinenko }
7113173a63fSAlex Zinenko 
7123173a63fSAlex Zinenko /// Create a deep copy of this operation, remapping any operands that use
7133173a63fSAlex Zinenko /// values outside of the operation using the map that is provided (leaving
7143173a63fSAlex Zinenko /// them alone if no entry is present).  Replaces references to cloned
7153173a63fSAlex Zinenko /// sub-operations to the corresponding operation that is copied, and adds
7163173a63fSAlex Zinenko /// those mappings to the map.
7174d67b278SJeff Niu Operation *Operation::clone(IRMapping &mapper, CloneOptions options) {
718a41aaf16SMarkus Böck   SmallVector<Value, 8> operands;
719a41aaf16SMarkus Böck   SmallVector<Block *, 2> successors;
720a41aaf16SMarkus Böck 
721a41aaf16SMarkus Böck   // Remap the operands.
722a41aaf16SMarkus Böck   if (options.shouldCloneOperands()) {
723a41aaf16SMarkus Böck     operands.reserve(getNumOperands());
724a41aaf16SMarkus Böck     for (auto opValue : getOperands())
725a41aaf16SMarkus Böck       operands.push_back(mapper.lookupOrDefault(opValue));
726a41aaf16SMarkus Böck   }
727a41aaf16SMarkus Böck 
728a41aaf16SMarkus Böck   // Remap the successors.
729a41aaf16SMarkus Böck   successors.reserve(getNumSuccessors());
730a41aaf16SMarkus Böck   for (Block *successor : getSuccessors())
731a41aaf16SMarkus Böck     successors.push_back(mapper.lookupOrDefault(successor));
732a41aaf16SMarkus Böck 
733a41aaf16SMarkus Böck   // Create the new operation.
734a41aaf16SMarkus Böck   auto *newOp = create(getLoc(), getName(), getResultTypes(), operands, attrs,
7355e118f93SMehdi Amini                        getPropertiesStorage(), successors, getNumRegions());
7364d67b278SJeff Niu   mapper.map(this, newOp);
7373173a63fSAlex Zinenko 
7389ffdc930SRiver Riddle   // Clone the regions.
739a41aaf16SMarkus Böck   if (options.shouldCloneRegions()) {
7409ffdc930SRiver Riddle     for (unsigned i = 0; i != numRegions; ++i)
741929466b5SRiver Riddle       getRegion(i).cloneInto(&newOp->getRegion(i), mapper);
742a41aaf16SMarkus Böck   }
7439ffdc930SRiver Riddle 
744a41aaf16SMarkus Böck   // Remember the mapping of any results.
745ed499ddcSWilliam S. Moses   for (unsigned i = 0, e = getNumResults(); i != e; ++i)
746ed499ddcSWilliam S. Moses     mapper.map(getResult(i), newOp->getResult(i));
747ed499ddcSWilliam S. Moses 
7489ffdc930SRiver Riddle   return newOp;
7499ffdc930SRiver Riddle }
7509ffdc930SRiver Riddle 
751a41aaf16SMarkus Böck Operation *Operation::clone(CloneOptions options) {
7524d67b278SJeff Niu   IRMapping mapper;
753a41aaf16SMarkus Böck   return clone(mapper, options);
7549ffdc930SRiver Riddle }
7559ffdc930SRiver Riddle 
7569ffdc930SRiver Riddle //===----------------------------------------------------------------------===//
757aed24ff5SChris Lattner // OpState trait class.
758c2f987b6SChris Lattner //===----------------------------------------------------------------------===//
759c2f987b6SChris Lattner 
7600845635eSMogball // The fallback for the parser is to try for a dialect operation parser.
7610845635eSMogball // Otherwise, reject the custom assembly form.
762729727ebSRiver Riddle ParseResult OpState::parse(OpAsmParser &parser, OperationState &result) {
7630845635eSMogball   if (auto parseFn = result.name.getDialect()->getParseOperationHook(
7640845635eSMogball           result.name.getStringRef()))
7650845635eSMogball     return (*parseFn)(parser, result);
7662797517eSRiver Riddle   return parser.emitError(parser.getNameLoc(), "has no custom assembly form");
7679eedf6adSChris Lattner }
7689eedf6adSChris Lattner 
7690845635eSMogball // The fallback for the printer is to try for a dialect operation printer.
7700845635eSMogball // Otherwise, it prints the generic form.
7710845635eSMogball void OpState::print(Operation *op, OpAsmPrinter &p, StringRef defaultDialect) {
7720845635eSMogball   if (auto printFn = op->getDialect()->getOperationPrinter(op)) {
7730845635eSMogball     printOpName(op, p, defaultDialect);
7740845635eSMogball     printFn(op, p);
7750845635eSMogball   } else {
7760845635eSMogball     p.printGenericOp(op);
7770845635eSMogball   }
7780845635eSMogball }
7790845635eSMogball 
780122e6858SAlex Zinenko /// Print an operation name, eliding the dialect prefix if necessary and doesn't
781122e6858SAlex Zinenko /// lead to ambiguities.
782387f9554SMehdi Amini void OpState::printOpName(Operation *op, OpAsmPrinter &p,
783387f9554SMehdi Amini                           StringRef defaultDialect) {
784c41b16c2SMehdi Amini   StringRef name = op->getName().getStringRef();
78588d319a2SKazu Hirata   if (name.starts_with((defaultDialect + ".").str()) && name.count('.') == 1)
786387f9554SMehdi Amini     name = name.drop_front(defaultDialect.size() + 1);
787c41b16c2SMehdi Amini   p.getStream() << name;
788c41b16c2SMehdi Amini }
7899eedf6adSChris Lattner 
7905e118f93SMehdi Amini /// Parse properties as a Attribute.
7915e118f93SMehdi Amini ParseResult OpState::genericParseProperties(OpAsmParser &parser,
7925e118f93SMehdi Amini                                             Attribute &result) {
793d488b222SBeal Wang   if (succeeded(parser.parseOptionalLess())) { // The less is optional.
794d488b222SBeal Wang     if (parser.parseAttribute(result) || parser.parseGreater())
7955e118f93SMehdi Amini       return failure();
796d488b222SBeal Wang   }
7975e118f93SMehdi Amini   return success();
7985e118f93SMehdi Amini }
7995e118f93SMehdi Amini 
800d488b222SBeal Wang /// Print the properties as a Attribute with names not included within
801d488b222SBeal Wang /// 'elidedProps'
802d488b222SBeal Wang void OpState::genericPrintProperties(OpAsmPrinter &p, Attribute properties,
803d488b222SBeal Wang                                      ArrayRef<StringRef> elidedProps) {
8044d60be04SBeal Wang   if (!properties)
8054d60be04SBeal Wang     return;
806d488b222SBeal Wang   auto dictAttr = dyn_cast_or_null<::mlir::DictionaryAttr>(properties);
807d488b222SBeal Wang   if (dictAttr && !elidedProps.empty()) {
808d488b222SBeal Wang     ArrayRef<NamedAttribute> attrs = dictAttr.getValue();
809d488b222SBeal Wang     llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedProps.begin(),
810d488b222SBeal Wang                                                   elidedProps.end());
811d488b222SBeal Wang     bool atLeastOneAttr = llvm::any_of(attrs, [&](NamedAttribute attr) {
812d488b222SBeal Wang       return !elidedAttrsSet.contains(attr.getName().strref());
813d488b222SBeal Wang     });
814d488b222SBeal Wang     if (atLeastOneAttr) {
815d488b222SBeal Wang       p << "<";
816d488b222SBeal Wang       p.printOptionalAttrDict(dictAttr.getValue(), elidedProps);
817d488b222SBeal Wang       p << ">";
818d488b222SBeal Wang     }
819d488b222SBeal Wang   } else {
8205e118f93SMehdi Amini     p << "<" << properties << ">";
8215e118f93SMehdi Amini   }
822d488b222SBeal Wang }
8235e118f93SMehdi Amini 
824c2f987b6SChris Lattner /// Emit an error about fatal conditions with this operation, reporting up to
825ff6e7cf5SRiver Riddle /// any diagnostic handlers that may be listening.
826ff6e7cf5SRiver Riddle InFlightDiagnostic OpState::emitError(const Twine &message) {
827f9d91531SRiver Riddle   return getOperation()->emitError(message);
828c2f987b6SChris Lattner }
829c2f987b6SChris Lattner 
830c2f987b6SChris Lattner /// Emit an error with the op name prefixed, like "'dim' op " which is
831c2f987b6SChris Lattner /// convenient for verifiers.
832ff6e7cf5SRiver Riddle InFlightDiagnostic OpState::emitOpError(const Twine &message) {
833f9d91531SRiver Riddle   return getOperation()->emitOpError(message);
834c2f987b6SChris Lattner }
835c2f987b6SChris Lattner 
836c2f987b6SChris Lattner /// Emit a warning about this operation, reporting up to any diagnostic
837c2f987b6SChris Lattner /// handlers that may be listening.
838ff6e7cf5SRiver Riddle InFlightDiagnostic OpState::emitWarning(const Twine &message) {
839ff6e7cf5SRiver Riddle   return getOperation()->emitWarning(message);
840c2f987b6SChris Lattner }
841c2f987b6SChris Lattner 
842b14c4b4cSRiver Riddle /// Emit a remark about this operation, reporting up to any diagnostic
843b14c4b4cSRiver Riddle /// handlers that may be listening.
844ff6e7cf5SRiver Riddle InFlightDiagnostic OpState::emitRemark(const Twine &message) {
845ff6e7cf5SRiver Riddle   return getOperation()->emitRemark(message);
846b14c4b4cSRiver Riddle }
847b14c4b4cSRiver Riddle 
848be8069ebSChris Lattner //===----------------------------------------------------------------------===//
849be8069ebSChris Lattner // Op Trait implementations
850be8069ebSChris Lattner //===----------------------------------------------------------------------===//
851be8069ebSChris Lattner 
852dd115e5aSMatthias Springer LogicalResult
853dd115e5aSMatthias Springer OpTrait::impl::foldCommutative(Operation *op, ArrayRef<Attribute> operands,
854dd115e5aSMatthias Springer                                SmallVectorImpl<OpFoldResult> &results) {
855dd115e5aSMatthias Springer   // Nothing to fold if there are not at least 2 operands.
856dd115e5aSMatthias Springer   if (op->getNumOperands() < 2)
857dd115e5aSMatthias Springer     return failure();
858dd115e5aSMatthias Springer   // Move all constant operands to the end.
859dd115e5aSMatthias Springer   OpOperand *operandsBegin = op->getOpOperands().begin();
860dd115e5aSMatthias Springer   auto isNonConstant = [&](OpOperand &o) {
861dd115e5aSMatthias Springer     return !static_cast<bool>(operands[std::distance(operandsBegin, &o)]);
862dd115e5aSMatthias Springer   };
863dd115e5aSMatthias Springer   auto *firstConstantIt = llvm::find_if_not(op->getOpOperands(), isNonConstant);
864dd115e5aSMatthias Springer   auto *newConstantIt = std::stable_partition(
865dd115e5aSMatthias Springer       firstConstantIt, op->getOpOperands().end(), isNonConstant);
866dd115e5aSMatthias Springer   // Return success if the op was modified.
867dd115e5aSMatthias Springer   return success(firstConstantIt != newConstantIt);
868dd115e5aSMatthias Springer }
869dd115e5aSMatthias Springer 
8707dff6b81Sahmedsabie OpFoldResult OpTrait::impl::foldIdempotent(Operation *op) {
871344eee6fSChris Jones   if (op->getNumOperands() == 1) {
8727dff6b81Sahmedsabie     auto *argumentOp = op->getOperand(0).getDefiningOp();
8737dff6b81Sahmedsabie     if (argumentOp && op->getName() == argumentOp->getName()) {
8747dff6b81Sahmedsabie       // Replace the outer operation output with the inner operation.
8757dff6b81Sahmedsabie       return op->getOperand(0);
8767dff6b81Sahmedsabie     }
877344eee6fSChris Jones   } else if (op->getOperand(0) == op->getOperand(1)) {
878344eee6fSChris Jones     return op->getOperand(0);
879344eee6fSChris Jones   }
8807dff6b81Sahmedsabie 
8817dff6b81Sahmedsabie   return {};
8827dff6b81Sahmedsabie }
8837dff6b81Sahmedsabie 
884c0b3abd1Sahmedsabie OpFoldResult OpTrait::impl::foldInvolution(Operation *op) {
885c0b3abd1Sahmedsabie   auto *argumentOp = op->getOperand(0).getDefiningOp();
886c0b3abd1Sahmedsabie   if (argumentOp && op->getName() == argumentOp->getName()) {
887c0b3abd1Sahmedsabie     // Replace the outer involutions output with inner's input.
888c0b3abd1Sahmedsabie     return argumentOp->getOperand(0);
889c0b3abd1Sahmedsabie   }
890c0b3abd1Sahmedsabie 
891c0b3abd1Sahmedsabie   return {};
892c0b3abd1Sahmedsabie }
893c0b3abd1Sahmedsabie 
89467a52c44SRiver Riddle LogicalResult OpTrait::impl::verifyZeroOperands(Operation *op) {
895c6e4aa9bSChris Lattner   if (op->getNumOperands() != 0)
896777e7b4fSRiver Riddle     return op->emitOpError() << "requires zero operands";
89767a52c44SRiver Riddle   return success();
898c6e4aa9bSChris Lattner }
899c6e4aa9bSChris Lattner 
90067a52c44SRiver Riddle LogicalResult OpTrait::impl::verifyOneOperand(Operation *op) {
901c6e4aa9bSChris Lattner   if (op->getNumOperands() != 1)
902777e7b4fSRiver Riddle     return op->emitOpError() << "requires a single operand";
90367a52c44SRiver Riddle   return success();
904c6e4aa9bSChris Lattner }
905c6e4aa9bSChris Lattner 
90667a52c44SRiver Riddle LogicalResult OpTrait::impl::verifyNOperands(Operation *op,
90767a52c44SRiver Riddle                                              unsigned numOperands) {
90882e55750SUday Bondhugula   if (op->getNumOperands() != numOperands) {
909777e7b4fSRiver Riddle     return op->emitOpError() << "expected " << numOperands
910777e7b4fSRiver Riddle                              << " operands, but found " << op->getNumOperands();
91182e55750SUday Bondhugula   }
91267a52c44SRiver Riddle   return success();
913c6e4aa9bSChris Lattner }
914c6e4aa9bSChris Lattner 
91567a52c44SRiver Riddle LogicalResult OpTrait::impl::verifyAtLeastNOperands(Operation *op,
916c6e4aa9bSChris Lattner                                                     unsigned numOperands) {
917c6e4aa9bSChris Lattner   if (op->getNumOperands() < numOperands)
918777e7b4fSRiver Riddle     return op->emitOpError()
919a91cfd19SUday Bondhugula            << "expected " << numOperands << " or more operands, but found "
920a91cfd19SUday Bondhugula            << op->getNumOperands();
92167a52c44SRiver Riddle   return success();
922c6e4aa9bSChris Lattner }
923c6e4aa9bSChris Lattner 
924559e816fSAlex Zinenko /// If this is a vector type, or a tensor type, return the scalar element type
925559e816fSAlex Zinenko /// that it is built around, otherwise return the type unmodified.
926559e816fSAlex Zinenko static Type getTensorOrVectorElementType(Type type) {
927c1fa60b4STres Popp   if (auto vec = llvm::dyn_cast<VectorType>(type))
928559e816fSAlex Zinenko     return vec.getElementType();
929559e816fSAlex Zinenko 
930559e816fSAlex Zinenko   // Look through tensor<vector<...>> to find the underlying element type.
931c1fa60b4STres Popp   if (auto tensor = llvm::dyn_cast<TensorType>(type))
932559e816fSAlex Zinenko     return getTensorOrVectorElementType(tensor.getElementType());
933559e816fSAlex Zinenko   return type;
934559e816fSAlex Zinenko }
935559e816fSAlex Zinenko 
9367dff6b81Sahmedsabie LogicalResult OpTrait::impl::verifyIsIdempotent(Operation *op) {
9377dff6b81Sahmedsabie   // FIXME: Add back check for no side effects on operation.
9387dff6b81Sahmedsabie   // Currently adding it would cause the shared library build
9397dff6b81Sahmedsabie   // to fail since there would be a dependency of IR on SideEffectInterfaces
9407dff6b81Sahmedsabie   // which is cyclical.
9417dff6b81Sahmedsabie   return success();
9427dff6b81Sahmedsabie }
9437dff6b81Sahmedsabie 
944c0b3abd1Sahmedsabie LogicalResult OpTrait::impl::verifyIsInvolution(Operation *op) {
945c0b3abd1Sahmedsabie   // FIXME: Add back check for no side effects on operation.
946c0b3abd1Sahmedsabie   // Currently adding it would cause the shared library build
947c0b3abd1Sahmedsabie   // to fail since there would be a dependency of IR on SideEffectInterfaces
948c0b3abd1Sahmedsabie   // which is cyclical.
949c0b3abd1Sahmedsabie   return success();
950c0b3abd1Sahmedsabie }
951c0b3abd1Sahmedsabie 
95235b68527SLei Zhang LogicalResult
95335b68527SLei Zhang OpTrait::impl::verifyOperandsAreSignlessIntegerLike(Operation *op) {
95406734badSRiver Riddle   for (auto opType : op->getOperandTypes()) {
95506734badSRiver Riddle     auto type = getTensorOrVectorElementType(opType);
95635b68527SLei Zhang     if (!type.isSignlessIntOrIndex())
957777e7b4fSRiver Riddle       return op->emitOpError() << "requires an integer or index type";
958559e816fSAlex Zinenko   }
95967a52c44SRiver Riddle   return success();
960559e816fSAlex Zinenko }
961559e816fSAlex Zinenko 
962c34386e3SGeoffrey Martin-Noble LogicalResult OpTrait::impl::verifyOperandsAreFloatLike(Operation *op) {
96306734badSRiver Riddle   for (auto opType : op->getOperandTypes()) {
96406734badSRiver Riddle     auto type = getTensorOrVectorElementType(opType);
965c1fa60b4STres Popp     if (!llvm::isa<FloatType>(type))
966c34386e3SGeoffrey Martin-Noble       return op->emitOpError("requires a float type");
967c34386e3SGeoffrey Martin-Noble   }
968c34386e3SGeoffrey Martin-Noble   return success();
969c34386e3SGeoffrey Martin-Noble }
970c34386e3SGeoffrey Martin-Noble 
97167a52c44SRiver Riddle LogicalResult OpTrait::impl::verifySameTypeOperands(Operation *op) {
972559e816fSAlex Zinenko   // Zero or one operand always have the "same" type.
973559e816fSAlex Zinenko   unsigned nOperands = op->getNumOperands();
974559e816fSAlex Zinenko   if (nOperands < 2)
97567a52c44SRiver Riddle     return success();
976559e816fSAlex Zinenko 
9772bdf33ccSRiver Riddle   auto type = op->getOperand(0).getType();
97806734badSRiver Riddle   for (auto opType : llvm::drop_begin(op->getOperandTypes(), 1))
97906734badSRiver Riddle     if (opType != type)
980777e7b4fSRiver Riddle       return op->emitOpError() << "requires all operands to have the same type";
98167a52c44SRiver Riddle   return success();
982559e816fSAlex Zinenko }
983559e816fSAlex Zinenko 
98470b69c54SMogball LogicalResult OpTrait::impl::verifyZeroRegions(Operation *op) {
9850359b86dSRiver Riddle   if (op->getNumRegions() != 0)
9860359b86dSRiver Riddle     return op->emitOpError() << "requires zero regions";
9870359b86dSRiver Riddle   return success();
9880359b86dSRiver Riddle }
9890359b86dSRiver Riddle 
9900359b86dSRiver Riddle LogicalResult OpTrait::impl::verifyOneRegion(Operation *op) {
9910359b86dSRiver Riddle   if (op->getNumRegions() != 1)
9920359b86dSRiver Riddle     return op->emitOpError() << "requires one region";
9930359b86dSRiver Riddle   return success();
9940359b86dSRiver Riddle }
9950359b86dSRiver Riddle 
9960359b86dSRiver Riddle LogicalResult OpTrait::impl::verifyNRegions(Operation *op,
9970359b86dSRiver Riddle                                             unsigned numRegions) {
9980359b86dSRiver Riddle   if (op->getNumRegions() != numRegions)
9990359b86dSRiver Riddle     return op->emitOpError() << "expected " << numRegions << " regions";
10000359b86dSRiver Riddle   return success();
10010359b86dSRiver Riddle }
10020359b86dSRiver Riddle 
10030359b86dSRiver Riddle LogicalResult OpTrait::impl::verifyAtLeastNRegions(Operation *op,
10040359b86dSRiver Riddle                                                    unsigned numRegions) {
10050359b86dSRiver Riddle   if (op->getNumRegions() < numRegions)
10060359b86dSRiver Riddle     return op->emitOpError() << "expected " << numRegions << " or more regions";
10070359b86dSRiver Riddle   return success();
10080359b86dSRiver Riddle }
10090359b86dSRiver Riddle 
101070b69c54SMogball LogicalResult OpTrait::impl::verifyZeroResults(Operation *op) {
1011c6e4aa9bSChris Lattner   if (op->getNumResults() != 0)
1012777e7b4fSRiver Riddle     return op->emitOpError() << "requires zero results";
101367a52c44SRiver Riddle   return success();
1014c6e4aa9bSChris Lattner }
1015c6e4aa9bSChris Lattner 
101667a52c44SRiver Riddle LogicalResult OpTrait::impl::verifyOneResult(Operation *op) {
1017c6e4aa9bSChris Lattner   if (op->getNumResults() != 1)
1018777e7b4fSRiver Riddle     return op->emitOpError() << "requires one result";
101967a52c44SRiver Riddle   return success();
1020c6e4aa9bSChris Lattner }
1021c6e4aa9bSChris Lattner 
102267a52c44SRiver Riddle LogicalResult OpTrait::impl::verifyNResults(Operation *op,
102367a52c44SRiver Riddle                                             unsigned numOperands) {
1024c6e4aa9bSChris Lattner   if (op->getNumResults() != numOperands)
1025777e7b4fSRiver Riddle     return op->emitOpError() << "expected " << numOperands << " results";
102667a52c44SRiver Riddle   return success();
1027c6e4aa9bSChris Lattner }
1028c6e4aa9bSChris Lattner 
102967a52c44SRiver Riddle LogicalResult OpTrait::impl::verifyAtLeastNResults(Operation *op,
103067a52c44SRiver Riddle                                                    unsigned numOperands) {
1031c6e4aa9bSChris Lattner   if (op->getNumResults() < numOperands)
1032777e7b4fSRiver Riddle     return op->emitOpError()
1033777e7b4fSRiver Riddle            << "expected " << numOperands << " or more results";
103467a52c44SRiver Riddle   return success();
1035c6e4aa9bSChris Lattner }
1036c6e4aa9bSChris Lattner 
1037c60c4903SStephan Herhut LogicalResult OpTrait::impl::verifySameOperandsShape(Operation *op) {
10388503ffbeSChristian Sigg   if (failed(verifyAtLeastNOperands(op, 1)))
1039c60c4903SStephan Herhut     return failure();
1040c60c4903SStephan Herhut 
104125a20b8aSTres Popp   if (failed(verifyCompatibleShapes(op->getOperandTypes())))
1042c60c4903SStephan Herhut     return op->emitOpError() << "requires the same shape for all operands";
104325a20b8aSTres Popp 
1044c60c4903SStephan Herhut   return success();
1045c60c4903SStephan Herhut }
1046c60c4903SStephan Herhut 
104767a52c44SRiver Riddle LogicalResult OpTrait::impl::verifySameOperandsAndResultShape(Operation *op) {
10488503ffbeSChristian Sigg   if (failed(verifyAtLeastNOperands(op, 1)) ||
10498503ffbeSChristian Sigg       failed(verifyAtLeastNResults(op, 1)))
105067a52c44SRiver Riddle     return failure();
10511f5330acSLei Zhang 
105225a20b8aSTres Popp   SmallVector<Type, 8> types(op->getOperandTypes());
105325a20b8aSTres Popp   types.append(llvm::to_vector<4>(op->getResultTypes()));
105425a20b8aSTres Popp 
105525a20b8aSTres Popp   if (failed(verifyCompatibleShapes(types)))
1056777e7b4fSRiver Riddle     return op->emitOpError()
1057777e7b4fSRiver Riddle            << "requires the same shape for all operands and results";
105825a20b8aSTres Popp 
105967a52c44SRiver Riddle   return success();
10601f5330acSLei Zhang }
10611f5330acSLei Zhang 
1062c60c4903SStephan Herhut LogicalResult OpTrait::impl::verifySameOperandsElementType(Operation *op) {
10638503ffbeSChristian Sigg   if (failed(verifyAtLeastNOperands(op, 1)))
1064c60c4903SStephan Herhut     return failure();
106518db4ce4SGeoffrey Martin-Noble   auto elementType = getElementTypeOrSelf(op->getOperand(0));
1066c60c4903SStephan Herhut 
106718db4ce4SGeoffrey Martin-Noble   for (auto operand : llvm::drop_begin(op->getOperands(), 1)) {
106818db4ce4SGeoffrey Martin-Noble     if (getElementTypeOrSelf(operand) != elementType)
1069c60c4903SStephan Herhut       return op->emitOpError("requires the same element type for all operands");
1070c60c4903SStephan Herhut   }
1071c60c4903SStephan Herhut 
1072c60c4903SStephan Herhut   return success();
1073c60c4903SStephan Herhut }
1074c60c4903SStephan Herhut 
1075dcab8011SJacques Pienaar LogicalResult
1076dcab8011SJacques Pienaar OpTrait::impl::verifySameOperandsAndResultElementType(Operation *op) {
10778503ffbeSChristian Sigg   if (failed(verifyAtLeastNOperands(op, 1)) ||
10788503ffbeSChristian Sigg       failed(verifyAtLeastNResults(op, 1)))
1079dcab8011SJacques Pienaar     return failure();
1080dcab8011SJacques Pienaar 
108118db4ce4SGeoffrey Martin-Noble   auto elementType = getElementTypeOrSelf(op->getResult(0));
1082dcab8011SJacques Pienaar 
1083dcab8011SJacques Pienaar   // Verify result element type matches first result's element type.
10849ed22ae5SRiver Riddle   for (auto result : llvm::drop_begin(op->getResults(), 1)) {
108518db4ce4SGeoffrey Martin-Noble     if (getElementTypeOrSelf(result) != elementType)
1086dcab8011SJacques Pienaar       return op->emitOpError(
1087dcab8011SJacques Pienaar           "requires the same element type for all operands and results");
1088dcab8011SJacques Pienaar   }
1089dcab8011SJacques Pienaar 
1090dcab8011SJacques Pienaar   // Verify operand's element type matches first result's element type.
1091dcab8011SJacques Pienaar   for (auto operand : op->getOperands()) {
109218db4ce4SGeoffrey Martin-Noble     if (getElementTypeOrSelf(operand) != elementType)
1093dcab8011SJacques Pienaar       return op->emitOpError(
1094dcab8011SJacques Pienaar           "requires the same element type for all operands and results");
1095dcab8011SJacques Pienaar   }
1096dcab8011SJacques Pienaar 
1097dcab8011SJacques Pienaar   return success();
1098dcab8011SJacques Pienaar }
1099dcab8011SJacques Pienaar 
110067a52c44SRiver Riddle LogicalResult OpTrait::impl::verifySameOperandsAndResultType(Operation *op) {
11018503ffbeSChristian Sigg   if (failed(verifyAtLeastNOperands(op, 1)) ||
11028503ffbeSChristian Sigg       failed(verifyAtLeastNResults(op, 1)))
110367a52c44SRiver Riddle     return failure();
11041f5330acSLei Zhang 
11052bdf33ccSRiver Riddle   auto type = op->getResult(0).getType();
110685b46314SSmit Hinsu   auto elementType = getElementTypeOrSelf(type);
1107829733afSJacques Pienaar   Attribute encoding = nullptr;
1108829733afSJacques Pienaar   if (auto rankedType = dyn_cast<RankedTensorType>(type))
1109829733afSJacques Pienaar     encoding = rankedType.getEncoding();
11103dfa8614SRiver Riddle   for (auto resultType : llvm::drop_begin(op->getResultTypes())) {
111185b46314SSmit Hinsu     if (getElementTypeOrSelf(resultType) != elementType ||
111285b46314SSmit Hinsu         failed(verifyCompatibleShape(resultType, type)))
1113777e7b4fSRiver Riddle       return op->emitOpError()
1114777e7b4fSRiver Riddle              << "requires the same type for all operands and results";
1115829733afSJacques Pienaar     if (encoding)
1116829733afSJacques Pienaar       if (auto rankedType = dyn_cast<RankedTensorType>(resultType);
1117829733afSJacques Pienaar           encoding != rankedType.getEncoding())
1118829733afSJacques Pienaar         return op->emitOpError()
1119829733afSJacques Pienaar                << "requires the same encoding for all operands and results";
1120be8069ebSChris Lattner   }
112106734badSRiver Riddle   for (auto opType : op->getOperandTypes()) {
112285b46314SSmit Hinsu     if (getElementTypeOrSelf(opType) != elementType ||
112385b46314SSmit Hinsu         failed(verifyCompatibleShape(opType, type)))
1124777e7b4fSRiver Riddle       return op->emitOpError()
1125777e7b4fSRiver Riddle              << "requires the same type for all operands and results";
1126829733afSJacques Pienaar     if (encoding)
1127829733afSJacques Pienaar       if (auto rankedType = dyn_cast<RankedTensorType>(opType);
1128829733afSJacques Pienaar           encoding != rankedType.getEncoding())
1129829733afSJacques Pienaar         return op->emitOpError()
1130829733afSJacques Pienaar                << "requires the same encoding for all operands and results";
1131be8069ebSChris Lattner   }
113267a52c44SRiver Riddle   return success();
1133be8069ebSChris Lattner }
1134be8069ebSChris Lattner 
113528fe1a4eSTai Ly LogicalResult OpTrait::impl::verifySameOperandsAndResultRank(Operation *op) {
113628fe1a4eSTai Ly   if (failed(verifyAtLeastNOperands(op, 1)))
113728fe1a4eSTai Ly     return failure();
113828fe1a4eSTai Ly 
113928fe1a4eSTai Ly   // delegate function that returns true if type is a shaped type with known
114028fe1a4eSTai Ly   // rank
114128fe1a4eSTai Ly   auto hasRank = [](const Type type) {
1142e8d09a5bSMehdi Amini     if (auto shapedType = dyn_cast<ShapedType>(type))
1143e8d09a5bSMehdi Amini       return shapedType.hasRank();
114428fe1a4eSTai Ly 
114528fe1a4eSTai Ly     return false;
114628fe1a4eSTai Ly   };
114728fe1a4eSTai Ly 
114828fe1a4eSTai Ly   auto rankedOperandTypes =
114928fe1a4eSTai Ly       llvm::make_filter_range(op->getOperandTypes(), hasRank);
115028fe1a4eSTai Ly   auto rankedResultTypes =
115128fe1a4eSTai Ly       llvm::make_filter_range(op->getResultTypes(), hasRank);
115228fe1a4eSTai Ly 
115328fe1a4eSTai Ly   // If all operands and results are unranked, then no further verification.
115428fe1a4eSTai Ly   if (rankedOperandTypes.empty() && rankedResultTypes.empty())
115528fe1a4eSTai Ly     return success();
115628fe1a4eSTai Ly 
115728fe1a4eSTai Ly   // delegate function that returns rank of shaped type with known rank
115828fe1a4eSTai Ly   auto getRank = [](const Type type) {
1159a5757c5bSChristian Sigg     return cast<ShapedType>(type).getRank();
116028fe1a4eSTai Ly   };
116128fe1a4eSTai Ly 
116228fe1a4eSTai Ly   auto rank = !rankedOperandTypes.empty() ? getRank(*rankedOperandTypes.begin())
116328fe1a4eSTai Ly                                           : getRank(*rankedResultTypes.begin());
116428fe1a4eSTai Ly 
116528fe1a4eSTai Ly   for (const auto type : rankedOperandTypes) {
116628fe1a4eSTai Ly     if (rank != getRank(type)) {
116728fe1a4eSTai Ly       return op->emitOpError("operands don't have matching ranks");
116828fe1a4eSTai Ly     }
116928fe1a4eSTai Ly   }
117028fe1a4eSTai Ly 
117128fe1a4eSTai Ly   for (const auto type : rankedResultTypes) {
117228fe1a4eSTai Ly     if (rank != getRank(type)) {
117328fe1a4eSTai Ly       return op->emitOpError("result type has different rank than operands");
117428fe1a4eSTai Ly     }
117528fe1a4eSTai Ly   }
117628fe1a4eSTai Ly 
117728fe1a4eSTai Ly   return success();
117828fe1a4eSTai Ly }
117928fe1a4eSTai Ly 
1180c0fd5e65SRiver Riddle LogicalResult OpTrait::impl::verifyIsTerminator(Operation *op) {
1181c0fd5e65SRiver Riddle   Block *block = op->getBlock();
1182c0fd5e65SRiver Riddle   // Verify that the operation is at the end of the respective parent block.
1183c0fd5e65SRiver Riddle   if (!block || &block->back() != op)
1184c0fd5e65SRiver Riddle     return op->emitOpError("must be the last operation in the parent block");
1185c0fd5e65SRiver Riddle   return success();
1186c0fd5e65SRiver Riddle }
1187c0fd5e65SRiver Riddle 
118867a52c44SRiver Riddle static LogicalResult verifyTerminatorSuccessors(Operation *op) {
11891e429540SRiver Riddle   auto *parent = op->getParentRegion();
119054cd6a7eSRiver Riddle 
11911807ba3cSRiver Riddle   // Verify that the operands lines up with the BB arguments in the successor.
1192621d7ccaSRiver Riddle   for (Block *succ : op->getSuccessors())
119354cd6a7eSRiver Riddle     if (succ->getParent() != parent)
119454cd6a7eSRiver Riddle       return op->emitError("reference to block defined in another region");
119567a52c44SRiver Riddle   return success();
11961807ba3cSRiver Riddle }
11971807ba3cSRiver Riddle 
119870b69c54SMogball LogicalResult OpTrait::impl::verifyZeroSuccessors(Operation *op) {
1199c0fd5e65SRiver Riddle   if (op->getNumSuccessors() != 0) {
1200c0fd5e65SRiver Riddle     return op->emitOpError("requires 0 successors but found ")
1201c0fd5e65SRiver Riddle            << op->getNumSuccessors();
1202c0fd5e65SRiver Riddle   }
120367a52c44SRiver Riddle   return success();
12048659f3faSRiver Riddle }
12058659f3faSRiver Riddle 
1206c0fd5e65SRiver Riddle LogicalResult OpTrait::impl::verifyOneSuccessor(Operation *op) {
1207c0fd5e65SRiver Riddle   if (op->getNumSuccessors() != 1) {
1208c0fd5e65SRiver Riddle     return op->emitOpError("requires 1 successor but found ")
1209c0fd5e65SRiver Riddle            << op->getNumSuccessors();
1210c0fd5e65SRiver Riddle   }
1211c0fd5e65SRiver Riddle   return verifyTerminatorSuccessors(op);
1212c0fd5e65SRiver Riddle }
1213c0fd5e65SRiver Riddle LogicalResult OpTrait::impl::verifyNSuccessors(Operation *op,
1214c0fd5e65SRiver Riddle                                                unsigned numSuccessors) {
1215c0fd5e65SRiver Riddle   if (op->getNumSuccessors() != numSuccessors) {
1216c0fd5e65SRiver Riddle     return op->emitOpError("requires ")
1217c0fd5e65SRiver Riddle            << numSuccessors << " successors but found "
1218c0fd5e65SRiver Riddle            << op->getNumSuccessors();
1219c0fd5e65SRiver Riddle   }
1220c0fd5e65SRiver Riddle   return verifyTerminatorSuccessors(op);
1221c0fd5e65SRiver Riddle }
1222c0fd5e65SRiver Riddle LogicalResult OpTrait::impl::verifyAtLeastNSuccessors(Operation *op,
1223c0fd5e65SRiver Riddle                                                       unsigned numSuccessors) {
1224c0fd5e65SRiver Riddle   if (op->getNumSuccessors() < numSuccessors) {
1225c0fd5e65SRiver Riddle     return op->emitOpError("requires at least ")
1226c0fd5e65SRiver Riddle            << numSuccessors << " successors but found "
1227c0fd5e65SRiver Riddle            << op->getNumSuccessors();
1228c0fd5e65SRiver Riddle   }
1229c0fd5e65SRiver Riddle   return verifyTerminatorSuccessors(op);
1230c0fd5e65SRiver Riddle }
1231c0fd5e65SRiver Riddle 
123267a52c44SRiver Riddle LogicalResult OpTrait::impl::verifyResultsAreBoolLike(Operation *op) {
123306734badSRiver Riddle   for (auto resultType : op->getResultTypes()) {
123406734badSRiver Riddle     auto elementType = getTensorOrVectorElementType(resultType);
123554948a43SRiver Riddle     bool isBoolType = elementType.isInteger(1);
12361f5330acSLei Zhang     if (!isBoolType)
1237777e7b4fSRiver Riddle       return op->emitOpError() << "requires a bool result type";
12381f5330acSLei Zhang   }
12391f5330acSLei Zhang 
124067a52c44SRiver Riddle   return success();
12411f5330acSLei Zhang }
12421f5330acSLei Zhang 
124367a52c44SRiver Riddle LogicalResult OpTrait::impl::verifyResultsAreFloatLike(Operation *op) {
124406734badSRiver Riddle   for (auto resultType : op->getResultTypes())
1245c1fa60b4STres Popp     if (!llvm::isa<FloatType>(getTensorOrVectorElementType(resultType)))
1246777e7b4fSRiver Riddle       return op->emitOpError() << "requires a floating point type";
124767a52c44SRiver Riddle 
124867a52c44SRiver Riddle   return success();
1249be8069ebSChris Lattner }
1250be8069ebSChris Lattner 
125135b68527SLei Zhang LogicalResult
125235b68527SLei Zhang OpTrait::impl::verifyResultsAreSignlessIntegerLike(Operation *op) {
125306734badSRiver Riddle   for (auto resultType : op->getResultTypes())
125435b68527SLei Zhang     if (!getTensorOrVectorElementType(resultType).isSignlessIntOrIndex())
1255777e7b4fSRiver Riddle       return op->emitOpError() << "requires an integer or index type";
125667a52c44SRiver Riddle   return success();
1257be8069ebSChris Lattner }
1258be8069ebSChris Lattner 
12594e103a12SRiver Riddle LogicalResult OpTrait::impl::verifyValueSizeAttr(Operation *op,
12604e103a12SRiver Riddle                                                  StringRef attrName,
12614e103a12SRiver Riddle                                                  StringRef valueGroupName,
12624e103a12SRiver Riddle                                                  size_t expectedCount) {
126358a47508SJeff Niu   auto sizeAttr = op->getAttrOfType<DenseI32ArrayAttr>(attrName);
126413c6e419SLei Zhang   if (!sizeAttr)
126558a47508SJeff Niu     return op->emitOpError("requires dense i32 array attribute '")
12664e103a12SRiver Riddle            << attrName << "'";
126713c6e419SLei Zhang 
126858a47508SJeff Niu   ArrayRef<int32_t> sizes = sizeAttr.asArrayRef();
126958a47508SJeff Niu   if (llvm::any_of(sizes, [](int32_t element) { return element < 0; }))
127013c6e419SLei Zhang     return op->emitOpError("'")
127113c6e419SLei Zhang            << attrName << "' attribute cannot have negative elements";
127213c6e419SLei Zhang 
127358a47508SJeff Niu   size_t totalCount =
127458a47508SJeff Niu       std::accumulate(sizes.begin(), sizes.end(), 0,
127558a47508SJeff Niu                       [](unsigned all, int32_t one) { return all + one; });
127613c6e419SLei Zhang 
12774e103a12SRiver Riddle   if (totalCount != expectedCount)
12784e103a12SRiver Riddle     return op->emitOpError()
12794e103a12SRiver Riddle            << valueGroupName << " count (" << expectedCount
12804e103a12SRiver Riddle            << ") does not match with the total size (" << totalCount
12814e103a12SRiver Riddle            << ") specified in attribute '" << attrName << "'";
128213c6e419SLei Zhang   return success();
128313c6e419SLei Zhang }
128413c6e419SLei Zhang 
128513c6e419SLei Zhang LogicalResult OpTrait::impl::verifyOperandSizeAttr(Operation *op,
128613c6e419SLei Zhang                                                    StringRef attrName) {
12874e103a12SRiver Riddle   return verifyValueSizeAttr(op, attrName, "operand", op->getNumOperands());
128813c6e419SLei Zhang }
128913c6e419SLei Zhang 
129013c6e419SLei Zhang LogicalResult OpTrait::impl::verifyResultSizeAttr(Operation *op,
129113c6e419SLei Zhang                                                   StringRef attrName) {
12924e103a12SRiver Riddle   return verifyValueSizeAttr(op, attrName, "result", op->getNumResults());
129313c6e419SLei Zhang }
129413c6e419SLei Zhang 
129552af9c59SRahul Joshi LogicalResult OpTrait::impl::verifyNoRegionArguments(Operation *op) {
129652af9c59SRahul Joshi   for (Region &region : op->getRegions()) {
129752af9c59SRahul Joshi     if (region.empty())
129852af9c59SRahul Joshi       continue;
129952af9c59SRahul Joshi 
1300e2b71610SRahul Joshi     if (region.getNumArguments() != 0) {
130152af9c59SRahul Joshi       if (op->getNumRegions() > 1)
130252af9c59SRahul Joshi         return op->emitOpError("region #")
130352af9c59SRahul Joshi                << region.getRegionNumber() << " should have no arguments";
130452af9c59SRahul Joshi       return op->emitOpError("region should have no arguments");
130552af9c59SRahul Joshi     }
130652af9c59SRahul Joshi   }
130752af9c59SRahul Joshi   return success();
130852af9c59SRahul Joshi }
130952af9c59SRahul Joshi 
1310bcc9b371SFrederik Gossen LogicalResult OpTrait::impl::verifyElementwise(Operation *op) {
1311971b8525SJakub Kuderski   auto isMappableType = llvm::IsaPred<VectorType, TensorType>;
1312*f4d75863SJakub Kuderski   auto resultMappableTypes =
1313*f4d75863SJakub Kuderski       llvm::filter_to_vector<1>(op->getResultTypes(), isMappableType);
1314*f4d75863SJakub Kuderski   auto operandMappableTypes =
1315*f4d75863SJakub Kuderski       llvm::filter_to_vector<2>(op->getOperandTypes(), isMappableType);
1316b4fa28b4SSean Silva 
1317b4fa28b4SSean Silva   // If the op only has scalar operand/result types, then we have nothing to
1318b4fa28b4SSean Silva   // check.
1319b4fa28b4SSean Silva   if (resultMappableTypes.empty() && operandMappableTypes.empty())
1320b4fa28b4SSean Silva     return success();
1321b4fa28b4SSean Silva 
1322b4fa28b4SSean Silva   if (!resultMappableTypes.empty() && operandMappableTypes.empty())
1323b4fa28b4SSean Silva     return op->emitOpError("if a result is non-scalar, then at least one "
1324b4fa28b4SSean Silva                            "operand must be non-scalar");
1325b4fa28b4SSean Silva 
1326b4fa28b4SSean Silva   assert(!operandMappableTypes.empty());
1327b4fa28b4SSean Silva 
1328b4fa28b4SSean Silva   if (resultMappableTypes.empty())
1329b4fa28b4SSean Silva     return op->emitOpError("if an operand is non-scalar, then there must be at "
1330b4fa28b4SSean Silva                            "least one non-scalar result");
1331b4fa28b4SSean Silva 
1332b4fa28b4SSean Silva   if (resultMappableTypes.size() != op->getNumResults())
1333b4fa28b4SSean Silva     return op->emitOpError(
1334b4fa28b4SSean Silva         "if an operand is non-scalar, then all results must be non-scalar");
1335b4fa28b4SSean Silva 
13362a71f957SFrederik Gossen   SmallVector<Type, 4> types = llvm::to_vector<2>(
13372a71f957SFrederik Gossen       llvm::concat<Type>(operandMappableTypes, resultMappableTypes));
13382a71f957SFrederik Gossen   TypeID expectedBaseTy = types.front().getTypeID();
13392a71f957SFrederik Gossen   if (!llvm::all_of(types,
13402a71f957SFrederik Gossen                     [&](Type t) { return t.getTypeID() == expectedBaseTy; }) ||
13412a71f957SFrederik Gossen       failed(verifyCompatibleShapes(types))) {
13422a71f957SFrederik Gossen     return op->emitOpError() << "all non-scalar operands/results must have the "
13432a71f957SFrederik Gossen                                 "same shape and base type";
1344b4fa28b4SSean Silva   }
1345b4fa28b4SSean Silva 
1346b4fa28b4SSean Silva   return success();
1347b4fa28b4SSean Silva }
1348b4fa28b4SSean Silva 
1349bde21b62SChris Lattner /// Check for any values used by operations regions attached to the
1350bde21b62SChris Lattner /// specified "IsIsolatedFromAbove" operation defined outside of it.
1351bde21b62SChris Lattner LogicalResult OpTrait::impl::verifyIsIsolatedFromAbove(Operation *isolatedOp) {
1352bde21b62SChris Lattner   assert(isolatedOp->hasTrait<OpTrait::IsIsolatedFromAbove>() &&
1353bde21b62SChris Lattner          "Intended to check IsolatedFromAbove ops");
1354bde21b62SChris Lattner 
1355bde21b62SChris Lattner   // List of regions to analyze.  Each region is processed independently, with
1356bde21b62SChris Lattner   // respect to the common `limit` region, so we can look at them in any order.
1357bde21b62SChris Lattner   // Therefore, use a simple vector and push/pop back the current region.
1358bde21b62SChris Lattner   SmallVector<Region *, 8> pendingRegions;
1359bde21b62SChris Lattner   for (auto &region : isolatedOp->getRegions()) {
1360bde21b62SChris Lattner     pendingRegions.push_back(&region);
1361bde21b62SChris Lattner 
1362bde21b62SChris Lattner     // Traverse all operations in the region.
1363bde21b62SChris Lattner     while (!pendingRegions.empty()) {
1364bde21b62SChris Lattner       for (Operation &op : pendingRegions.pop_back_val()->getOps()) {
1365bde21b62SChris Lattner         for (Value operand : op.getOperands()) {
1366bde21b62SChris Lattner           // Check that any value that is used by an operation is defined in the
1367bde21b62SChris Lattner           // same region as either an operation result.
1368bde21b62SChris Lattner           auto *operandRegion = operand.getParentRegion();
136927df7158SSergei Grechanik           if (!operandRegion)
137027df7158SSergei Grechanik             return op.emitError("operation's operand is unlinked");
1371bde21b62SChris Lattner           if (!region.isAncestor(operandRegion)) {
1372bde21b62SChris Lattner             return op.emitOpError("using value defined outside the region")
1373bde21b62SChris Lattner                        .attachNote(isolatedOp->getLoc())
1374bde21b62SChris Lattner                    << "required by region isolation constraints";
1375bde21b62SChris Lattner           }
1376bde21b62SChris Lattner         }
1377bde21b62SChris Lattner 
1378bde21b62SChris Lattner         // Schedule any regions in the operation for further checking.  Don't
1379bde21b62SChris Lattner         // recurse into other IsolatedFromAbove ops, because they will check
1380bde21b62SChris Lattner         // themselves.
1381bde21b62SChris Lattner         if (op.getNumRegions() &&
1382bde21b62SChris Lattner             !op.hasTrait<OpTrait::IsIsolatedFromAbove>()) {
1383bde21b62SChris Lattner           for (Region &subRegion : op.getRegions())
1384bde21b62SChris Lattner             pendingRegions.push_back(&subRegion);
1385bde21b62SChris Lattner         }
1386bde21b62SChris Lattner       }
1387bde21b62SChris Lattner     }
1388bde21b62SChris Lattner   }
1389bde21b62SChris Lattner 
1390bde21b62SChris Lattner   return success();
1391bde21b62SChris Lattner }
1392bde21b62SChris Lattner 
1393bcc9b371SFrederik Gossen bool OpTrait::hasElementwiseMappableTraits(Operation *op) {
1394bcc9b371SFrederik Gossen   return op->hasTrait<Elementwise>() && op->hasTrait<Scalarizable>() &&
1395bcc9b371SFrederik Gossen          op->hasTrait<Vectorizable>() && op->hasTrait<Tensorizable>();
1396bcc9b371SFrederik Gossen }
1397bcc9b371SFrederik Gossen 
1398be8069ebSChris Lattner //===----------------------------------------------------------------------===//
13999ed22ae5SRiver Riddle // Misc. utils
140025734596SRiver Riddle //===----------------------------------------------------------------------===//
140125734596SRiver Riddle 
140225734596SRiver Riddle /// Insert an operation, generated by `buildTerminatorOp`, at the end of the
140325734596SRiver Riddle /// region's only block if it does not have a terminator already. If the region
140425734596SRiver Riddle /// is empty, insert a new block first. `buildTerminatorOp` should return the
140525734596SRiver Riddle /// terminator operation to insert.
140625734596SRiver Riddle void impl::ensureRegionTerminator(
14073ccf4a5bSAlex Zinenko     Region &region, OpBuilder &builder, Location loc,
14083ccf4a5bSAlex Zinenko     function_ref<Operation *(OpBuilder &, Location)> buildTerminatorOp) {
14093ccf4a5bSAlex Zinenko   OpBuilder::InsertionGuard guard(builder);
141025734596SRiver Riddle   if (region.empty())
14113ccf4a5bSAlex Zinenko     builder.createBlock(&region);
141225734596SRiver Riddle 
141325734596SRiver Riddle   Block &block = region.back();
1414fe7c0d90SRiver Riddle   if (!block.empty() && block.back().hasTrait<OpTrait::IsTerminator>())
141525734596SRiver Riddle     return;
141625734596SRiver Riddle 
14173ccf4a5bSAlex Zinenko   builder.setInsertionPointToEnd(&block);
14183ccf4a5bSAlex Zinenko   builder.insert(buildTerminatorOp(builder, loc));
14193ccf4a5bSAlex Zinenko }
14203ccf4a5bSAlex Zinenko 
14213ccf4a5bSAlex Zinenko /// Create a simple OpBuilder and forward to the OpBuilder version of this
14223ccf4a5bSAlex Zinenko /// function.
14233ccf4a5bSAlex Zinenko void impl::ensureRegionTerminator(
14243ccf4a5bSAlex Zinenko     Region &region, Builder &builder, Location loc,
14253ccf4a5bSAlex Zinenko     function_ref<Operation *(OpBuilder &, Location)> buildTerminatorOp) {
14263ccf4a5bSAlex Zinenko   OpBuilder opBuilder(builder.getContext());
14273ccf4a5bSAlex Zinenko   ensureRegionTerminator(region, opBuilder, loc, buildTerminatorOp);
142825734596SRiver Riddle }
1429