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 ®ion : 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 ®ion : 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 ®ion : 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 ®ion : 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 ®ion : isolatedOp->getRegions()) { 1360bde21b62SChris Lattner pendingRegions.push_back(®ion); 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 ®ion, 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(®ion); 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 ®ion, 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