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