1 //===- OpImplementation.h - Classes for implementing Op types ---*- C++ -*-===// 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 // This classes used by the implementation details of Op types. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef MLIR_IR_OPIMPLEMENTATION_H 14 #define MLIR_IR_OPIMPLEMENTATION_H 15 16 #include "mlir/IR/BuiltinTypes.h" 17 #include "mlir/IR/DialectInterface.h" 18 #include "mlir/IR/OpDefinition.h" 19 #include "llvm/ADT/Twine.h" 20 #include "llvm/Support/SMLoc.h" 21 #include <optional> 22 23 namespace mlir { 24 class AsmParsedResourceEntry; 25 class AsmResourceBuilder; 26 class Builder; 27 28 //===----------------------------------------------------------------------===// 29 // AsmDialectResourceHandle 30 //===----------------------------------------------------------------------===// 31 32 /// This class represents an opaque handle to a dialect resource entry. 33 class AsmDialectResourceHandle { 34 public: 35 AsmDialectResourceHandle() = default; 36 AsmDialectResourceHandle(void *resource, TypeID resourceID, Dialect *dialect) 37 : resource(resource), opaqueID(resourceID), dialect(dialect) {} 38 bool operator==(const AsmDialectResourceHandle &other) const { 39 return resource == other.resource; 40 } 41 42 /// Return an opaque pointer to the referenced resource. 43 void *getResource() const { return resource; } 44 45 /// Return the type ID of the resource. 46 TypeID getTypeID() const { return opaqueID; } 47 48 /// Return the dialect that owns the resource. 49 Dialect *getDialect() const { return dialect; } 50 51 private: 52 /// The opaque handle to the dialect resource. 53 void *resource = nullptr; 54 /// The type of the resource referenced. 55 TypeID opaqueID; 56 /// The dialect owning the given resource. 57 Dialect *dialect; 58 }; 59 60 /// This class represents a CRTP base class for dialect resource handles. It 61 /// abstracts away various utilities necessary for defined derived resource 62 /// handles. 63 template <typename DerivedT, typename ResourceT, typename DialectT> 64 class AsmDialectResourceHandleBase : public AsmDialectResourceHandle { 65 public: 66 using Dialect = DialectT; 67 68 /// Construct a handle from a pointer to the resource. The given pointer 69 /// should be guaranteed to live beyond the life of this handle. 70 AsmDialectResourceHandleBase(ResourceT *resource, DialectT *dialect) 71 : AsmDialectResourceHandle(resource, TypeID::get<DerivedT>(), dialect) {} 72 AsmDialectResourceHandleBase(AsmDialectResourceHandle handle) 73 : AsmDialectResourceHandle(handle) { 74 assert(handle.getTypeID() == TypeID::get<DerivedT>()); 75 } 76 77 /// Return the resource referenced by this handle. 78 ResourceT *getResource() { 79 return static_cast<ResourceT *>(AsmDialectResourceHandle::getResource()); 80 } 81 const ResourceT *getResource() const { 82 return const_cast<AsmDialectResourceHandleBase *>(this)->getResource(); 83 } 84 85 /// Return the dialect that owns the resource. 86 DialectT *getDialect() const { 87 return static_cast<DialectT *>(AsmDialectResourceHandle::getDialect()); 88 } 89 90 /// Support llvm style casting. 91 static bool classof(const AsmDialectResourceHandle *handle) { 92 return handle->getTypeID() == TypeID::get<DerivedT>(); 93 } 94 }; 95 96 inline llvm::hash_code hash_value(const AsmDialectResourceHandle ¶m) { 97 return llvm::hash_value(param.getResource()); 98 } 99 100 //===----------------------------------------------------------------------===// 101 // AsmPrinter 102 //===----------------------------------------------------------------------===// 103 104 /// This base class exposes generic asm printer hooks, usable across the various 105 /// derived printers. 106 class AsmPrinter { 107 public: 108 /// This class contains the internal default implementation of the base 109 /// printer methods. 110 class Impl; 111 112 /// Initialize the printer with the given internal implementation. 113 AsmPrinter(Impl &impl) : impl(&impl) {} 114 virtual ~AsmPrinter(); 115 116 /// Return the raw output stream used by this printer. 117 virtual raw_ostream &getStream() const; 118 119 /// Print the given floating point value in a stabilized form that can be 120 /// roundtripped through the IR. This is the companion to the 'parseFloat' 121 /// hook on the AsmParser. 122 virtual void printFloat(const APFloat &value); 123 124 virtual void printType(Type type); 125 virtual void printAttribute(Attribute attr); 126 127 /// Trait to check if `AttrType` provides a `print` method. 128 template <typename AttrOrType> 129 using has_print_method = 130 decltype(std::declval<AttrOrType>().print(std::declval<AsmPrinter &>())); 131 template <typename AttrOrType> 132 using detect_has_print_method = 133 llvm::is_detected<has_print_method, AttrOrType>; 134 135 /// Print the provided attribute in the context of an operation custom 136 /// printer/parser: this will invoke directly the print method on the 137 /// attribute class and skip the `#dialect.mnemonic` prefix in most cases. 138 template <typename AttrOrType, 139 std::enable_if_t<detect_has_print_method<AttrOrType>::value> 140 *sfinae = nullptr> 141 void printStrippedAttrOrType(AttrOrType attrOrType) { 142 if (succeeded(printAlias(attrOrType))) 143 return; 144 145 raw_ostream &os = getStream(); 146 uint64_t posPrior = os.tell(); 147 attrOrType.print(*this); 148 if (posPrior != os.tell()) 149 return; 150 151 // Fallback to printing with prefix if the above failed to write anything 152 // to the output stream. 153 *this << attrOrType; 154 } 155 156 /// Print the provided array of attributes or types in the context of an 157 /// operation custom printer/parser: this will invoke directly the print 158 /// method on the attribute class and skip the `#dialect.mnemonic` prefix in 159 /// most cases. 160 template <typename AttrOrType, 161 std::enable_if_t<detect_has_print_method<AttrOrType>::value> 162 *sfinae = nullptr> 163 void printStrippedAttrOrType(ArrayRef<AttrOrType> attrOrTypes) { 164 llvm::interleaveComma( 165 attrOrTypes, getStream(), 166 [this](AttrOrType attrOrType) { printStrippedAttrOrType(attrOrType); }); 167 } 168 169 /// SFINAE for printing the provided attribute in the context of an operation 170 /// custom printer in the case where the attribute does not define a print 171 /// method. 172 template <typename AttrOrType, 173 std::enable_if_t<!detect_has_print_method<AttrOrType>::value> 174 *sfinae = nullptr> 175 void printStrippedAttrOrType(AttrOrType attrOrType) { 176 *this << attrOrType; 177 } 178 179 /// Print the given attribute without its type. The corresponding parser must 180 /// provide a valid type for the attribute. 181 virtual void printAttributeWithoutType(Attribute attr); 182 183 /// Print the alias for the given attribute, return failure if no alias could 184 /// be printed. 185 virtual LogicalResult printAlias(Attribute attr); 186 187 /// Print the alias for the given type, return failure if no alias could 188 /// be printed. 189 virtual LogicalResult printAlias(Type type); 190 191 /// Print the given string as a keyword, or a quoted and escaped string if it 192 /// has any special or non-printable characters in it. 193 virtual void printKeywordOrString(StringRef keyword); 194 195 /// Print the given string as a quoted string, escaping any special or 196 /// non-printable characters in it. 197 virtual void printString(StringRef string); 198 199 /// Print the given string as a symbol reference, i.e. a form representable by 200 /// a SymbolRefAttr. A symbol reference is represented as a string prefixed 201 /// with '@'. The reference is surrounded with ""'s and escaped if it has any 202 /// special or non-printable characters in it. 203 virtual void printSymbolName(StringRef symbolRef); 204 205 /// Print a handle to the given dialect resource. 206 virtual void printResourceHandle(const AsmDialectResourceHandle &resource); 207 208 /// Print an optional arrow followed by a type list. 209 template <typename TypeRange> 210 void printOptionalArrowTypeList(TypeRange &&types) { 211 if (types.begin() != types.end()) 212 printArrowTypeList(types); 213 } 214 template <typename TypeRange> 215 void printArrowTypeList(TypeRange &&types) { 216 auto &os = getStream() << " -> "; 217 218 bool wrapped = !llvm::hasSingleElement(types) || 219 llvm::isa<FunctionType>((*types.begin())); 220 if (wrapped) 221 os << '('; 222 llvm::interleaveComma(types, *this); 223 if (wrapped) 224 os << ')'; 225 } 226 227 /// Print the two given type ranges in a functional form. 228 template <typename InputRangeT, typename ResultRangeT> 229 void printFunctionalType(InputRangeT &&inputs, ResultRangeT &&results) { 230 auto &os = getStream(); 231 os << '('; 232 llvm::interleaveComma(inputs, *this); 233 os << ')'; 234 printArrowTypeList(results); 235 } 236 237 void printDimensionList(ArrayRef<int64_t> shape); 238 239 /// Class used to automatically end a cyclic region on destruction. 240 class CyclicPrintReset { 241 public: 242 explicit CyclicPrintReset(AsmPrinter *printer) : printer(printer) {} 243 244 ~CyclicPrintReset() { 245 if (printer) 246 printer->popCyclicPrinting(); 247 } 248 249 CyclicPrintReset(const CyclicPrintReset &) = delete; 250 251 CyclicPrintReset &operator=(const CyclicPrintReset &) = delete; 252 253 CyclicPrintReset(CyclicPrintReset &&rhs) 254 : printer(std::exchange(rhs.printer, nullptr)) {} 255 256 CyclicPrintReset &operator=(CyclicPrintReset &&rhs) { 257 printer = std::exchange(rhs.printer, nullptr); 258 return *this; 259 } 260 261 private: 262 AsmPrinter *printer; 263 }; 264 265 /// Attempts to start a cyclic printing region for `attrOrType`. 266 /// A cyclic printing region starts with this call and ends with the 267 /// destruction of the returned `CyclicPrintReset`. During this time, 268 /// calling `tryStartCyclicPrint` with the same attribute in any printer 269 /// will lead to returning failure. 270 /// 271 /// This makes it possible to break infinite recursions when trying to print 272 /// cyclic attributes or types by printing only immutable parameters if nested 273 /// within itself. 274 template <class AttrOrTypeT> 275 FailureOr<CyclicPrintReset> tryStartCyclicPrint(AttrOrTypeT attrOrType) { 276 static_assert( 277 std::is_base_of_v<AttributeTrait::IsMutable<AttrOrTypeT>, 278 AttrOrTypeT> || 279 std::is_base_of_v<TypeTrait::IsMutable<AttrOrTypeT>, AttrOrTypeT>, 280 "Only mutable attributes or types can be cyclic"); 281 if (failed(pushCyclicPrinting(attrOrType.getAsOpaquePointer()))) 282 return failure(); 283 return CyclicPrintReset(this); 284 } 285 286 protected: 287 /// Initialize the printer with no internal implementation. In this case, all 288 /// virtual methods of this class must be overriden. 289 AsmPrinter() = default; 290 291 /// Pushes a new attribute or type in the form of a type erased pointer 292 /// into an internal set. 293 /// Returns success if the type or attribute was inserted in the set or 294 /// failure if it was already contained. 295 virtual LogicalResult pushCyclicPrinting(const void *opaquePointer); 296 297 /// Removes the element that was last inserted with a successful call to 298 /// `pushCyclicPrinting`. There must be exactly one `popCyclicPrinting` call 299 /// in reverse order of all successful `pushCyclicPrinting`. 300 virtual void popCyclicPrinting(); 301 302 private: 303 AsmPrinter(const AsmPrinter &) = delete; 304 void operator=(const AsmPrinter &) = delete; 305 306 /// The internal implementation of the printer. 307 Impl *impl{nullptr}; 308 }; 309 310 template <typename AsmPrinterT> 311 inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value, 312 AsmPrinterT &> 313 operator<<(AsmPrinterT &p, Type type) { 314 p.printType(type); 315 return p; 316 } 317 318 template <typename AsmPrinterT> 319 inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value, 320 AsmPrinterT &> 321 operator<<(AsmPrinterT &p, Attribute attr) { 322 p.printAttribute(attr); 323 return p; 324 } 325 326 template <typename AsmPrinterT> 327 inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value, 328 AsmPrinterT &> 329 operator<<(AsmPrinterT &p, const APFloat &value) { 330 p.printFloat(value); 331 return p; 332 } 333 template <typename AsmPrinterT> 334 inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value, 335 AsmPrinterT &> 336 operator<<(AsmPrinterT &p, float value) { 337 return p << APFloat(value); 338 } 339 template <typename AsmPrinterT> 340 inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value, 341 AsmPrinterT &> 342 operator<<(AsmPrinterT &p, double value) { 343 return p << APFloat(value); 344 } 345 346 // Support printing anything that isn't convertible to one of the other 347 // streamable types, even if it isn't exactly one of them. For example, we want 348 // to print FunctionType with the Type version above, not have it match this. 349 template <typename AsmPrinterT, typename T, 350 std::enable_if_t<!std::is_convertible<T &, Value &>::value && 351 !std::is_convertible<T &, Type &>::value && 352 !std::is_convertible<T &, Attribute &>::value && 353 !std::is_convertible<T &, ValueRange>::value && 354 !std::is_convertible<T &, APFloat &>::value && 355 !llvm::is_one_of<T, bool, float, double>::value, 356 T> * = nullptr> 357 inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value, 358 AsmPrinterT &> 359 operator<<(AsmPrinterT &p, const T &other) { 360 p.getStream() << other; 361 return p; 362 } 363 364 template <typename AsmPrinterT> 365 inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value, 366 AsmPrinterT &> 367 operator<<(AsmPrinterT &p, bool value) { 368 return p << (value ? StringRef("true") : "false"); 369 } 370 371 template <typename AsmPrinterT, typename ValueRangeT> 372 inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value, 373 AsmPrinterT &> 374 operator<<(AsmPrinterT &p, const ValueTypeRange<ValueRangeT> &types) { 375 llvm::interleaveComma(types, p); 376 return p; 377 } 378 379 template <typename AsmPrinterT> 380 inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value, 381 AsmPrinterT &> 382 operator<<(AsmPrinterT &p, const TypeRange &types) { 383 llvm::interleaveComma(types, p); 384 return p; 385 } 386 387 // Prevent matching the TypeRange version above for ValueRange 388 // printing through base AsmPrinter. This is needed so that the 389 // ValueRange printing behaviour does not change from printing 390 // the SSA values to printing the types for the operands when 391 // using AsmPrinter instead of OpAsmPrinter. 392 template <typename AsmPrinterT, typename T> 393 inline std::enable_if_t<std::is_same<AsmPrinter, AsmPrinterT>::value && 394 std::is_convertible<T &, ValueRange>::value, 395 AsmPrinterT &> 396 operator<<(AsmPrinterT &p, const T &other) = delete; 397 398 template <typename AsmPrinterT, typename ElementT> 399 inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value, 400 AsmPrinterT &> 401 operator<<(AsmPrinterT &p, ArrayRef<ElementT> types) { 402 llvm::interleaveComma(types, p); 403 return p; 404 } 405 406 //===----------------------------------------------------------------------===// 407 // OpAsmPrinter 408 //===----------------------------------------------------------------------===// 409 410 /// This is a pure-virtual base class that exposes the asmprinter hooks 411 /// necessary to implement a custom print() method. 412 class OpAsmPrinter : public AsmPrinter { 413 public: 414 using AsmPrinter::AsmPrinter; 415 ~OpAsmPrinter() override; 416 417 /// Print a loc(...) specifier if printing debug info is enabled. 418 virtual void printOptionalLocationSpecifier(Location loc) = 0; 419 420 /// Print a newline and indent the printer to the start of the current 421 /// operation. 422 virtual void printNewline() = 0; 423 424 /// Increase indentation. 425 virtual void increaseIndent() = 0; 426 427 /// Decrease indentation. 428 virtual void decreaseIndent() = 0; 429 430 /// Print a block argument in the usual format of: 431 /// %ssaName : type {attr1=42} loc("here") 432 /// where location printing is controlled by the standard internal option. 433 /// You may pass omitType=true to not print a type, and pass an empty 434 /// attribute list if you don't care for attributes. 435 virtual void printRegionArgument(BlockArgument arg, 436 ArrayRef<NamedAttribute> argAttrs = {}, 437 bool omitType = false) = 0; 438 439 /// Print implementations for various things an operation contains. 440 virtual void printOperand(Value value) = 0; 441 virtual void printOperand(Value value, raw_ostream &os) = 0; 442 443 /// Print a comma separated list of operands. 444 template <typename ContainerType> 445 void printOperands(const ContainerType &container) { 446 printOperands(container.begin(), container.end()); 447 } 448 449 /// Print a comma separated list of operands. 450 template <typename IteratorType> 451 void printOperands(IteratorType it, IteratorType end) { 452 llvm::interleaveComma(llvm::make_range(it, end), getStream(), 453 [this](Value value) { printOperand(value); }); 454 } 455 456 /// Print the given successor. 457 virtual void printSuccessor(Block *successor) = 0; 458 459 /// Print the successor and its operands. 460 virtual void printSuccessorAndUseList(Block *successor, 461 ValueRange succOperands) = 0; 462 463 /// If the specified operation has attributes, print out an attribute 464 /// dictionary with their values. elidedAttrs allows the client to ignore 465 /// specific well known attributes, commonly used if the attribute value is 466 /// printed some other way (like as a fixed operand). 467 virtual void printOptionalAttrDict(ArrayRef<NamedAttribute> attrs, 468 ArrayRef<StringRef> elidedAttrs = {}) = 0; 469 470 /// If the specified operation has attributes, print out an attribute 471 /// dictionary prefixed with 'attributes'. 472 virtual void 473 printOptionalAttrDictWithKeyword(ArrayRef<NamedAttribute> attrs, 474 ArrayRef<StringRef> elidedAttrs = {}) = 0; 475 476 /// Prints the entire operation with the custom assembly form, if available, 477 /// or the generic assembly form, otherwise. 478 virtual void printCustomOrGenericOp(Operation *op) = 0; 479 480 /// Print the entire operation with the default generic assembly form. 481 /// If `printOpName` is true, then the operation name is printed (the default) 482 /// otherwise it is omitted and the print will start with the operand list. 483 virtual void printGenericOp(Operation *op, bool printOpName = true) = 0; 484 485 /// Prints a region. 486 /// If 'printEntryBlockArgs' is false, the arguments of the 487 /// block are not printed. If 'printBlockTerminator' is false, the terminator 488 /// operation of the block is not printed. If printEmptyBlock is true, then 489 /// the block header is printed even if the block is empty. 490 virtual void printRegion(Region &blocks, bool printEntryBlockArgs = true, 491 bool printBlockTerminators = true, 492 bool printEmptyBlock = false) = 0; 493 494 /// Renumber the arguments for the specified region to the same names as the 495 /// SSA values in namesToUse. This may only be used for IsolatedFromAbove 496 /// operations. If any entry in namesToUse is null, the corresponding 497 /// argument name is left alone. 498 virtual void shadowRegionArgs(Region ®ion, ValueRange namesToUse) = 0; 499 500 /// Prints an affine map of SSA ids, where SSA id names are used in place 501 /// of dims/symbols. 502 /// Operand values must come from single-result sources, and be valid 503 /// dimensions/symbol identifiers according to mlir::isValidDim/Symbol. 504 virtual void printAffineMapOfSSAIds(AffineMapAttr mapAttr, 505 ValueRange operands) = 0; 506 507 /// Prints an affine expression of SSA ids with SSA id names used instead of 508 /// dims and symbols. 509 /// Operand values must come from single-result sources, and be valid 510 /// dimensions/symbol identifiers according to mlir::isValidDim/Symbol. 511 virtual void printAffineExprOfSSAIds(AffineExpr expr, ValueRange dimOperands, 512 ValueRange symOperands) = 0; 513 514 /// Print the complete type of an operation in functional form. 515 void printFunctionalType(Operation *op); 516 using AsmPrinter::printFunctionalType; 517 }; 518 519 // Make the implementations convenient to use. 520 inline OpAsmPrinter &operator<<(OpAsmPrinter &p, Value value) { 521 p.printOperand(value); 522 return p; 523 } 524 525 template <typename T, 526 std::enable_if_t<std::is_convertible<T &, ValueRange>::value && 527 !std::is_convertible<T &, Value &>::value, 528 T> * = nullptr> 529 inline OpAsmPrinter &operator<<(OpAsmPrinter &p, const T &values) { 530 p.printOperands(values); 531 return p; 532 } 533 534 inline OpAsmPrinter &operator<<(OpAsmPrinter &p, Block *value) { 535 p.printSuccessor(value); 536 return p; 537 } 538 539 //===----------------------------------------------------------------------===// 540 // AsmParser 541 //===----------------------------------------------------------------------===// 542 543 /// This base class exposes generic asm parser hooks, usable across the various 544 /// derived parsers. 545 class AsmParser { 546 public: 547 AsmParser() = default; 548 virtual ~AsmParser(); 549 550 MLIRContext *getContext() const; 551 552 /// Return the location of the original name token. 553 virtual SMLoc getNameLoc() const = 0; 554 555 //===--------------------------------------------------------------------===// 556 // Utilities 557 //===--------------------------------------------------------------------===// 558 559 /// Emit a diagnostic at the specified location and return failure. 560 virtual InFlightDiagnostic emitError(SMLoc loc, 561 const Twine &message = {}) = 0; 562 563 /// Return a builder which provides useful access to MLIRContext, global 564 /// objects like types and attributes. 565 virtual Builder &getBuilder() const = 0; 566 567 /// Get the location of the next token and store it into the argument. This 568 /// always succeeds. 569 virtual SMLoc getCurrentLocation() = 0; 570 ParseResult getCurrentLocation(SMLoc *loc) { 571 *loc = getCurrentLocation(); 572 return success(); 573 } 574 575 /// Re-encode the given source location as an MLIR location and return it. 576 /// Note: This method should only be used when a `Location` is necessary, as 577 /// the encoding process is not efficient. 578 virtual Location getEncodedSourceLoc(SMLoc loc) = 0; 579 580 //===--------------------------------------------------------------------===// 581 // Token Parsing 582 //===--------------------------------------------------------------------===// 583 584 /// Parse a '->' token. 585 virtual ParseResult parseArrow() = 0; 586 587 /// Parse a '->' token if present 588 virtual ParseResult parseOptionalArrow() = 0; 589 590 /// Parse a `{` token. 591 virtual ParseResult parseLBrace() = 0; 592 593 /// Parse a `{` token if present. 594 virtual ParseResult parseOptionalLBrace() = 0; 595 596 /// Parse a `}` token. 597 virtual ParseResult parseRBrace() = 0; 598 599 /// Parse a `}` token if present. 600 virtual ParseResult parseOptionalRBrace() = 0; 601 602 /// Parse a `:` token. 603 virtual ParseResult parseColon() = 0; 604 605 /// Parse a `:` token if present. 606 virtual ParseResult parseOptionalColon() = 0; 607 608 /// Parse a `,` token. 609 virtual ParseResult parseComma() = 0; 610 611 /// Parse a `,` token if present. 612 virtual ParseResult parseOptionalComma() = 0; 613 614 /// Parse a `=` token. 615 virtual ParseResult parseEqual() = 0; 616 617 /// Parse a `=` token if present. 618 virtual ParseResult parseOptionalEqual() = 0; 619 620 /// Parse a '<' token. 621 virtual ParseResult parseLess() = 0; 622 623 /// Parse a '<' token if present. 624 virtual ParseResult parseOptionalLess() = 0; 625 626 /// Parse a '>' token. 627 virtual ParseResult parseGreater() = 0; 628 629 /// Parse a '>' token if present. 630 virtual ParseResult parseOptionalGreater() = 0; 631 632 /// Parse a '?' token. 633 virtual ParseResult parseQuestion() = 0; 634 635 /// Parse a '?' token if present. 636 virtual ParseResult parseOptionalQuestion() = 0; 637 638 /// Parse a '+' token. 639 virtual ParseResult parsePlus() = 0; 640 641 /// Parse a '+' token if present. 642 virtual ParseResult parseOptionalPlus() = 0; 643 644 /// Parse a '-' token. 645 virtual ParseResult parseMinus() = 0; 646 647 /// Parse a '-' token if present. 648 virtual ParseResult parseOptionalMinus() = 0; 649 650 /// Parse a '*' token. 651 virtual ParseResult parseStar() = 0; 652 653 /// Parse a '*' token if present. 654 virtual ParseResult parseOptionalStar() = 0; 655 656 /// Parse a '|' token. 657 virtual ParseResult parseVerticalBar() = 0; 658 659 /// Parse a '|' token if present. 660 virtual ParseResult parseOptionalVerticalBar() = 0; 661 662 /// Parse a quoted string token. 663 ParseResult parseString(std::string *string) { 664 auto loc = getCurrentLocation(); 665 if (parseOptionalString(string)) 666 return emitError(loc, "expected string"); 667 return success(); 668 } 669 670 /// Parse a quoted string token if present. 671 virtual ParseResult parseOptionalString(std::string *string) = 0; 672 673 /// Parses a Base64 encoded string of bytes. 674 virtual ParseResult parseBase64Bytes(std::vector<char> *bytes) = 0; 675 676 /// Parse a `(` token. 677 virtual ParseResult parseLParen() = 0; 678 679 /// Parse a `(` token if present. 680 virtual ParseResult parseOptionalLParen() = 0; 681 682 /// Parse a `)` token. 683 virtual ParseResult parseRParen() = 0; 684 685 /// Parse a `)` token if present. 686 virtual ParseResult parseOptionalRParen() = 0; 687 688 /// Parse a `[` token. 689 virtual ParseResult parseLSquare() = 0; 690 691 /// Parse a `[` token if present. 692 virtual ParseResult parseOptionalLSquare() = 0; 693 694 /// Parse a `]` token. 695 virtual ParseResult parseRSquare() = 0; 696 697 /// Parse a `]` token if present. 698 virtual ParseResult parseOptionalRSquare() = 0; 699 700 /// Parse a `...` token. 701 virtual ParseResult parseEllipsis() = 0; 702 703 /// Parse a `...` token if present; 704 virtual ParseResult parseOptionalEllipsis() = 0; 705 706 /// Parse a floating point value from the stream. 707 virtual ParseResult parseFloat(double &result) = 0; 708 709 /// Parse a floating point value into APFloat from the stream. 710 virtual ParseResult parseFloat(const llvm::fltSemantics &semantics, 711 APFloat &result) = 0; 712 713 /// Parse an integer value from the stream. 714 template <typename IntT> 715 ParseResult parseInteger(IntT &result) { 716 auto loc = getCurrentLocation(); 717 OptionalParseResult parseResult = parseOptionalInteger(result); 718 if (!parseResult.has_value()) 719 return emitError(loc, "expected integer value"); 720 return *parseResult; 721 } 722 723 /// Parse a decimal integer value from the stream. 724 template <typename IntT> 725 ParseResult parseDecimalInteger(IntT &result) { 726 auto loc = getCurrentLocation(); 727 OptionalParseResult parseResult = parseOptionalDecimalInteger(result); 728 if (!parseResult.has_value()) 729 return emitError(loc, "expected decimal integer value"); 730 return *parseResult; 731 } 732 733 /// Parse an optional integer value from the stream. 734 virtual OptionalParseResult parseOptionalInteger(APInt &result) = 0; 735 virtual OptionalParseResult parseOptionalDecimalInteger(APInt &result) = 0; 736 737 private: 738 template <typename IntT, typename ParseFn> 739 OptionalParseResult parseOptionalIntegerAndCheck(IntT &result, 740 ParseFn &&parseFn) { 741 auto loc = getCurrentLocation(); 742 APInt uintResult; 743 OptionalParseResult parseResult = parseFn(uintResult); 744 if (!parseResult.has_value() || failed(*parseResult)) 745 return parseResult; 746 747 // Try to convert to the provided integer type. sextOrTrunc is correct even 748 // for unsigned types because parseOptionalInteger ensures the sign bit is 749 // zero for non-negated integers. 750 result = 751 (IntT)uintResult.sextOrTrunc(sizeof(IntT) * CHAR_BIT).getLimitedValue(); 752 if (APInt(uintResult.getBitWidth(), result, 753 /*isSigned=*/std::is_signed_v<IntT>, 754 /*implicitTrunc=*/true) != uintResult) 755 return emitError(loc, "integer value too large"); 756 return success(); 757 } 758 759 public: 760 template <typename IntT> 761 OptionalParseResult parseOptionalInteger(IntT &result) { 762 return parseOptionalIntegerAndCheck( 763 result, [&](APInt &result) { return parseOptionalInteger(result); }); 764 } 765 766 template <typename IntT> 767 OptionalParseResult parseOptionalDecimalInteger(IntT &result) { 768 return parseOptionalIntegerAndCheck(result, [&](APInt &result) { 769 return parseOptionalDecimalInteger(result); 770 }); 771 } 772 773 /// These are the supported delimiters around operand lists and region 774 /// argument lists, used by parseOperandList. 775 enum class Delimiter { 776 /// Zero or more operands with no delimiters. 777 None, 778 /// Parens surrounding zero or more operands. 779 Paren, 780 /// Square brackets surrounding zero or more operands. 781 Square, 782 /// <> brackets surrounding zero or more operands. 783 LessGreater, 784 /// {} brackets surrounding zero or more operands. 785 Braces, 786 /// Parens supporting zero or more operands, or nothing. 787 OptionalParen, 788 /// Square brackets supporting zero or more ops, or nothing. 789 OptionalSquare, 790 /// <> brackets supporting zero or more ops, or nothing. 791 OptionalLessGreater, 792 /// {} brackets surrounding zero or more operands, or nothing. 793 OptionalBraces, 794 }; 795 796 /// Parse a list of comma-separated items with an optional delimiter. If a 797 /// delimiter is provided, then an empty list is allowed. If not, then at 798 /// least one element will be parsed. 799 /// 800 /// contextMessage is an optional message appended to "expected '('" sorts of 801 /// diagnostics when parsing the delimeters. 802 virtual ParseResult 803 parseCommaSeparatedList(Delimiter delimiter, 804 function_ref<ParseResult()> parseElementFn, 805 StringRef contextMessage = StringRef()) = 0; 806 807 /// Parse a comma separated list of elements that must have at least one entry 808 /// in it. 809 ParseResult 810 parseCommaSeparatedList(function_ref<ParseResult()> parseElementFn) { 811 return parseCommaSeparatedList(Delimiter::None, parseElementFn); 812 } 813 814 //===--------------------------------------------------------------------===// 815 // Keyword Parsing 816 //===--------------------------------------------------------------------===// 817 818 /// This class represents a StringSwitch like class that is useful for parsing 819 /// expected keywords. On construction, unless a non-empty keyword is 820 /// provided, it invokes `parseKeyword` and processes each of the provided 821 /// cases statements until a match is hit. The provided `ResultT` must be 822 /// assignable from `failure()`. 823 template <typename ResultT = ParseResult> 824 class KeywordSwitch { 825 public: 826 KeywordSwitch(AsmParser &parser, StringRef *keyword = nullptr) 827 : parser(parser), loc(parser.getCurrentLocation()) { 828 if (keyword && !keyword->empty()) 829 this->keyword = *keyword; 830 else if (failed(parser.parseKeywordOrCompletion(&this->keyword))) 831 result = failure(); 832 } 833 /// Case that uses the provided value when true. 834 KeywordSwitch &Case(StringLiteral str, ResultT value) { 835 return Case(str, [&](StringRef, SMLoc) { return std::move(value); }); 836 } 837 KeywordSwitch &Default(ResultT value) { 838 return Default([&](StringRef, SMLoc) { return std::move(value); }); 839 } 840 /// Case that invokes the provided functor when true. The parameters passed 841 /// to the functor are the keyword, and the location of the keyword (in case 842 /// any errors need to be emitted). 843 template <typename FnT> 844 std::enable_if_t<!std::is_convertible<FnT, ResultT>::value, KeywordSwitch &> 845 Case(StringLiteral str, FnT &&fn) { 846 if (result) 847 return *this; 848 849 // If the word was empty, record this as a completion. 850 if (keyword.empty()) 851 parser.codeCompleteExpectedTokens(str); 852 else if (keyword == str) 853 result.emplace(std::move(fn(keyword, loc))); 854 return *this; 855 } 856 template <typename FnT> 857 std::enable_if_t<!std::is_convertible<FnT, ResultT>::value, KeywordSwitch &> 858 Default(FnT &&fn) { 859 if (!result) 860 result.emplace(fn(keyword, loc)); 861 return *this; 862 } 863 864 /// Returns true if this switch has a value yet. 865 bool hasValue() const { return result.has_value(); } 866 867 /// Return the result of the switch. 868 [[nodiscard]] operator ResultT() { 869 if (!result) 870 return parser.emitError(loc, "unexpected keyword: ") << keyword; 871 return std::move(*result); 872 } 873 874 private: 875 /// The parser used to construct this switch. 876 AsmParser &parser; 877 878 /// The location of the keyword, used to emit errors as necessary. 879 SMLoc loc; 880 881 /// The parsed keyword itself. 882 StringRef keyword; 883 884 /// The result of the switch statement or std::nullopt if currently unknown. 885 std::optional<ResultT> result; 886 }; 887 888 /// Parse a given keyword. 889 ParseResult parseKeyword(StringRef keyword) { 890 return parseKeyword(keyword, ""); 891 } 892 virtual ParseResult parseKeyword(StringRef keyword, const Twine &msg) = 0; 893 894 /// Parse a keyword into 'keyword'. 895 ParseResult parseKeyword(StringRef *keyword) { 896 auto loc = getCurrentLocation(); 897 if (parseOptionalKeyword(keyword)) 898 return emitError(loc, "expected valid keyword"); 899 return success(); 900 } 901 902 /// Parse the given keyword if present. 903 virtual ParseResult parseOptionalKeyword(StringRef keyword) = 0; 904 905 /// Parse a keyword, if present, into 'keyword'. 906 virtual ParseResult parseOptionalKeyword(StringRef *keyword) = 0; 907 908 /// Parse a keyword, if present, and if one of the 'allowedValues', 909 /// into 'keyword' 910 virtual ParseResult 911 parseOptionalKeyword(StringRef *keyword, 912 ArrayRef<StringRef> allowedValues) = 0; 913 914 /// Parse a keyword or a quoted string. 915 ParseResult parseKeywordOrString(std::string *result) { 916 if (failed(parseOptionalKeywordOrString(result))) 917 return emitError(getCurrentLocation()) 918 << "expected valid keyword or string"; 919 return success(); 920 } 921 922 /// Parse an optional keyword or string. 923 virtual ParseResult parseOptionalKeywordOrString(std::string *result) = 0; 924 925 //===--------------------------------------------------------------------===// 926 // Attribute/Type Parsing 927 //===--------------------------------------------------------------------===// 928 929 /// Invoke the `getChecked` method of the given Attribute or Type class, using 930 /// the provided location to emit errors in the case of failure. Note that 931 /// unlike `OpBuilder::getType`, this method does not implicitly insert a 932 /// context parameter. 933 template <typename T, typename... ParamsT> 934 auto getChecked(SMLoc loc, ParamsT &&...params) { 935 return T::getChecked([&] { return emitError(loc); }, 936 std::forward<ParamsT>(params)...); 937 } 938 /// A variant of `getChecked` that uses the result of `getNameLoc` to emit 939 /// errors. 940 template <typename T, typename... ParamsT> 941 auto getChecked(ParamsT &&...params) { 942 return T::getChecked([&] { return emitError(getNameLoc()); }, 943 std::forward<ParamsT>(params)...); 944 } 945 946 //===--------------------------------------------------------------------===// 947 // Attribute Parsing 948 //===--------------------------------------------------------------------===// 949 950 /// Parse an arbitrary attribute of a given type and return it in result. 951 virtual ParseResult parseAttribute(Attribute &result, Type type = {}) = 0; 952 953 /// Parse a custom attribute with the provided callback, unless the next 954 /// token is `#`, in which case the generic parser is invoked. 955 virtual ParseResult parseCustomAttributeWithFallback( 956 Attribute &result, Type type, 957 function_ref<ParseResult(Attribute &result, Type type)> 958 parseAttribute) = 0; 959 960 /// Parse an attribute of a specific kind and type. 961 template <typename AttrType> 962 ParseResult parseAttribute(AttrType &result, Type type = {}) { 963 SMLoc loc = getCurrentLocation(); 964 965 // Parse any kind of attribute. 966 Attribute attr; 967 if (parseAttribute(attr, type)) 968 return failure(); 969 970 // Check for the right kind of attribute. 971 if (!(result = llvm::dyn_cast<AttrType>(attr))) 972 return emitError(loc, "invalid kind of attribute specified"); 973 974 return success(); 975 } 976 977 /// Parse an arbitrary attribute and return it in result. This also adds the 978 /// attribute to the specified attribute list with the specified name. 979 ParseResult parseAttribute(Attribute &result, StringRef attrName, 980 NamedAttrList &attrs) { 981 return parseAttribute(result, Type(), attrName, attrs); 982 } 983 984 /// Parse an attribute of a specific kind and type. 985 template <typename AttrType> 986 ParseResult parseAttribute(AttrType &result, StringRef attrName, 987 NamedAttrList &attrs) { 988 return parseAttribute(result, Type(), attrName, attrs); 989 } 990 991 /// Parse an arbitrary attribute of a given type and populate it in `result`. 992 /// This also adds the attribute to the specified attribute list with the 993 /// specified name. 994 template <typename AttrType> 995 ParseResult parseAttribute(AttrType &result, Type type, StringRef attrName, 996 NamedAttrList &attrs) { 997 SMLoc loc = getCurrentLocation(); 998 999 // Parse any kind of attribute. 1000 Attribute attr; 1001 if (parseAttribute(attr, type)) 1002 return failure(); 1003 1004 // Check for the right kind of attribute. 1005 result = llvm::dyn_cast<AttrType>(attr); 1006 if (!result) 1007 return emitError(loc, "invalid kind of attribute specified"); 1008 1009 attrs.append(attrName, result); 1010 return success(); 1011 } 1012 1013 /// Trait to check if `AttrType` provides a `parse` method. 1014 template <typename AttrType> 1015 using has_parse_method = decltype(AttrType::parse(std::declval<AsmParser &>(), 1016 std::declval<Type>())); 1017 template <typename AttrType> 1018 using detect_has_parse_method = llvm::is_detected<has_parse_method, AttrType>; 1019 1020 /// Parse a custom attribute of a given type unless the next token is `#`, in 1021 /// which case the generic parser is invoked. The parsed attribute is 1022 /// populated in `result` and also added to the specified attribute list with 1023 /// the specified name. 1024 template <typename AttrType> 1025 std::enable_if_t<detect_has_parse_method<AttrType>::value, ParseResult> 1026 parseCustomAttributeWithFallback(AttrType &result, Type type, 1027 StringRef attrName, NamedAttrList &attrs) { 1028 SMLoc loc = getCurrentLocation(); 1029 1030 // Parse any kind of attribute. 1031 Attribute attr; 1032 if (parseCustomAttributeWithFallback( 1033 attr, type, [&](Attribute &result, Type type) -> ParseResult { 1034 result = AttrType::parse(*this, type); 1035 if (!result) 1036 return failure(); 1037 return success(); 1038 })) 1039 return failure(); 1040 1041 // Check for the right kind of attribute. 1042 result = llvm::dyn_cast<AttrType>(attr); 1043 if (!result) 1044 return emitError(loc, "invalid kind of attribute specified"); 1045 1046 attrs.append(attrName, result); 1047 return success(); 1048 } 1049 1050 /// SFINAE parsing method for Attribute that don't implement a parse method. 1051 template <typename AttrType> 1052 std::enable_if_t<!detect_has_parse_method<AttrType>::value, ParseResult> 1053 parseCustomAttributeWithFallback(AttrType &result, Type type, 1054 StringRef attrName, NamedAttrList &attrs) { 1055 return parseAttribute(result, type, attrName, attrs); 1056 } 1057 1058 /// Parse a custom attribute of a given type unless the next token is `#`, in 1059 /// which case the generic parser is invoked. The parsed attribute is 1060 /// populated in `result`. 1061 template <typename AttrType> 1062 std::enable_if_t<detect_has_parse_method<AttrType>::value, ParseResult> 1063 parseCustomAttributeWithFallback(AttrType &result, Type type = {}) { 1064 SMLoc loc = getCurrentLocation(); 1065 1066 // Parse any kind of attribute. 1067 Attribute attr; 1068 if (parseCustomAttributeWithFallback( 1069 attr, type, [&](Attribute &result, Type type) -> ParseResult { 1070 result = AttrType::parse(*this, type); 1071 return success(!!result); 1072 })) 1073 return failure(); 1074 1075 // Check for the right kind of attribute. 1076 result = llvm::dyn_cast<AttrType>(attr); 1077 if (!result) 1078 return emitError(loc, "invalid kind of attribute specified"); 1079 return success(); 1080 } 1081 1082 /// SFINAE parsing method for Attribute that don't implement a parse method. 1083 template <typename AttrType> 1084 std::enable_if_t<!detect_has_parse_method<AttrType>::value, ParseResult> 1085 parseCustomAttributeWithFallback(AttrType &result, Type type = {}) { 1086 return parseAttribute(result, type); 1087 } 1088 1089 /// Parse an arbitrary optional attribute of a given type and return it in 1090 /// result. 1091 virtual OptionalParseResult parseOptionalAttribute(Attribute &result, 1092 Type type = {}) = 0; 1093 1094 /// Parse an optional array attribute and return it in result. 1095 virtual OptionalParseResult parseOptionalAttribute(ArrayAttr &result, 1096 Type type = {}) = 0; 1097 1098 /// Parse an optional string attribute and return it in result. 1099 virtual OptionalParseResult parseOptionalAttribute(StringAttr &result, 1100 Type type = {}) = 0; 1101 1102 /// Parse an optional symbol ref attribute and return it in result. 1103 virtual OptionalParseResult parseOptionalAttribute(SymbolRefAttr &result, 1104 Type type = {}) = 0; 1105 1106 /// Parse an optional attribute of a specific type and add it to the list with 1107 /// the specified name. 1108 template <typename AttrType> 1109 OptionalParseResult parseOptionalAttribute(AttrType &result, 1110 StringRef attrName, 1111 NamedAttrList &attrs) { 1112 return parseOptionalAttribute(result, Type(), attrName, attrs); 1113 } 1114 1115 /// Parse an optional attribute of a specific type and add it to the list with 1116 /// the specified name. 1117 template <typename AttrType> 1118 OptionalParseResult parseOptionalAttribute(AttrType &result, Type type, 1119 StringRef attrName, 1120 NamedAttrList &attrs) { 1121 OptionalParseResult parseResult = parseOptionalAttribute(result, type); 1122 if (parseResult.has_value() && succeeded(*parseResult)) 1123 attrs.append(attrName, result); 1124 return parseResult; 1125 } 1126 1127 /// Parse a named dictionary into 'result' if it is present. 1128 virtual ParseResult parseOptionalAttrDict(NamedAttrList &result) = 0; 1129 1130 /// Parse a named dictionary into 'result' if the `attributes` keyword is 1131 /// present. 1132 virtual ParseResult 1133 parseOptionalAttrDictWithKeyword(NamedAttrList &result) = 0; 1134 1135 /// Parse an affine map instance into 'map'. 1136 virtual ParseResult parseAffineMap(AffineMap &map) = 0; 1137 1138 /// Parse an affine expr instance into 'expr' using the already computed 1139 /// mapping from symbols to affine expressions in 'symbolSet'. 1140 virtual ParseResult 1141 parseAffineExpr(ArrayRef<std::pair<StringRef, AffineExpr>> symbolSet, 1142 AffineExpr &expr) = 0; 1143 1144 /// Parse an integer set instance into 'set'. 1145 virtual ParseResult parseIntegerSet(IntegerSet &set) = 0; 1146 1147 //===--------------------------------------------------------------------===// 1148 // Identifier Parsing 1149 //===--------------------------------------------------------------------===// 1150 1151 /// Parse an @-identifier and store it (without the '@' symbol) in a string 1152 /// attribute. 1153 ParseResult parseSymbolName(StringAttr &result) { 1154 if (failed(parseOptionalSymbolName(result))) 1155 return emitError(getCurrentLocation()) 1156 << "expected valid '@'-identifier for symbol name"; 1157 return success(); 1158 } 1159 1160 /// Parse an @-identifier and store it (without the '@' symbol) in a string 1161 /// attribute named 'attrName'. 1162 ParseResult parseSymbolName(StringAttr &result, StringRef attrName, 1163 NamedAttrList &attrs) { 1164 if (parseSymbolName(result)) 1165 return failure(); 1166 attrs.append(attrName, result); 1167 return success(); 1168 } 1169 1170 /// Parse an optional @-identifier and store it (without the '@' symbol) in a 1171 /// string attribute. 1172 virtual ParseResult parseOptionalSymbolName(StringAttr &result) = 0; 1173 1174 /// Parse an optional @-identifier and store it (without the '@' symbol) in a 1175 /// string attribute named 'attrName'. 1176 ParseResult parseOptionalSymbolName(StringAttr &result, StringRef attrName, 1177 NamedAttrList &attrs) { 1178 if (succeeded(parseOptionalSymbolName(result))) { 1179 attrs.append(attrName, result); 1180 return success(); 1181 } 1182 return failure(); 1183 } 1184 1185 //===--------------------------------------------------------------------===// 1186 // Resource Parsing 1187 //===--------------------------------------------------------------------===// 1188 1189 /// Parse a handle to a resource within the assembly format. 1190 template <typename ResourceT> 1191 FailureOr<ResourceT> parseResourceHandle() { 1192 SMLoc handleLoc = getCurrentLocation(); 1193 1194 // Try to load the dialect that owns the handle. 1195 auto *dialect = 1196 getContext()->getOrLoadDialect<typename ResourceT::Dialect>(); 1197 if (!dialect) { 1198 return emitError(handleLoc) 1199 << "dialect '" << ResourceT::Dialect::getDialectNamespace() 1200 << "' is unknown"; 1201 } 1202 1203 FailureOr<AsmDialectResourceHandle> handle = parseResourceHandle(dialect); 1204 if (failed(handle)) 1205 return failure(); 1206 if (auto *result = dyn_cast<ResourceT>(&*handle)) 1207 return std::move(*result); 1208 return emitError(handleLoc) << "provided resource handle differs from the " 1209 "expected resource type"; 1210 } 1211 1212 //===--------------------------------------------------------------------===// 1213 // Type Parsing 1214 //===--------------------------------------------------------------------===// 1215 1216 /// Parse a type. 1217 virtual ParseResult parseType(Type &result) = 0; 1218 1219 /// Parse a custom type with the provided callback, unless the next 1220 /// token is `#`, in which case the generic parser is invoked. 1221 virtual ParseResult parseCustomTypeWithFallback( 1222 Type &result, function_ref<ParseResult(Type &result)> parseType) = 0; 1223 1224 /// Parse an optional type. 1225 virtual OptionalParseResult parseOptionalType(Type &result) = 0; 1226 1227 /// Parse a type of a specific type. 1228 template <typename TypeT> 1229 ParseResult parseType(TypeT &result) { 1230 SMLoc loc = getCurrentLocation(); 1231 1232 // Parse any kind of type. 1233 Type type; 1234 if (parseType(type)) 1235 return failure(); 1236 1237 // Check for the right kind of type. 1238 result = llvm::dyn_cast<TypeT>(type); 1239 if (!result) 1240 return emitError(loc, "invalid kind of type specified"); 1241 1242 return success(); 1243 } 1244 1245 /// Trait to check if `TypeT` provides a `parse` method. 1246 template <typename TypeT> 1247 using type_has_parse_method = 1248 decltype(TypeT::parse(std::declval<AsmParser &>())); 1249 template <typename TypeT> 1250 using detect_type_has_parse_method = 1251 llvm::is_detected<type_has_parse_method, TypeT>; 1252 1253 /// Parse a custom Type of a given type unless the next token is `#`, in 1254 /// which case the generic parser is invoked. The parsed Type is 1255 /// populated in `result`. 1256 template <typename TypeT> 1257 std::enable_if_t<detect_type_has_parse_method<TypeT>::value, ParseResult> 1258 parseCustomTypeWithFallback(TypeT &result) { 1259 SMLoc loc = getCurrentLocation(); 1260 1261 // Parse any kind of Type. 1262 Type type; 1263 if (parseCustomTypeWithFallback(type, [&](Type &result) -> ParseResult { 1264 result = TypeT::parse(*this); 1265 return success(!!result); 1266 })) 1267 return failure(); 1268 1269 // Check for the right kind of Type. 1270 result = llvm::dyn_cast<TypeT>(type); 1271 if (!result) 1272 return emitError(loc, "invalid kind of Type specified"); 1273 return success(); 1274 } 1275 1276 /// SFINAE parsing method for Type that don't implement a parse method. 1277 template <typename TypeT> 1278 std::enable_if_t<!detect_type_has_parse_method<TypeT>::value, ParseResult> 1279 parseCustomTypeWithFallback(TypeT &result) { 1280 return parseType(result); 1281 } 1282 1283 /// Parse a type list. 1284 ParseResult parseTypeList(SmallVectorImpl<Type> &result); 1285 1286 /// Parse an arrow followed by a type list. 1287 virtual ParseResult parseArrowTypeList(SmallVectorImpl<Type> &result) = 0; 1288 1289 /// Parse an optional arrow followed by a type list. 1290 virtual ParseResult 1291 parseOptionalArrowTypeList(SmallVectorImpl<Type> &result) = 0; 1292 1293 /// Parse a colon followed by a type. 1294 virtual ParseResult parseColonType(Type &result) = 0; 1295 1296 /// Parse a colon followed by a type of a specific kind, e.g. a FunctionType. 1297 template <typename TypeType> 1298 ParseResult parseColonType(TypeType &result) { 1299 SMLoc loc = getCurrentLocation(); 1300 1301 // Parse any kind of type. 1302 Type type; 1303 if (parseColonType(type)) 1304 return failure(); 1305 1306 // Check for the right kind of type. 1307 result = llvm::dyn_cast<TypeType>(type); 1308 if (!result) 1309 return emitError(loc, "invalid kind of type specified"); 1310 1311 return success(); 1312 } 1313 1314 /// Parse a colon followed by a type list, which must have at least one type. 1315 virtual ParseResult parseColonTypeList(SmallVectorImpl<Type> &result) = 0; 1316 1317 /// Parse an optional colon followed by a type list, which if present must 1318 /// have at least one type. 1319 virtual ParseResult 1320 parseOptionalColonTypeList(SmallVectorImpl<Type> &result) = 0; 1321 1322 /// Parse a keyword followed by a type. 1323 ParseResult parseKeywordType(const char *keyword, Type &result) { 1324 return failure(parseKeyword(keyword) || parseType(result)); 1325 } 1326 1327 /// Add the specified type to the end of the specified type list and return 1328 /// success. This is a helper designed to allow parse methods to be simple 1329 /// and chain through || operators. 1330 ParseResult addTypeToList(Type type, SmallVectorImpl<Type> &result) { 1331 result.push_back(type); 1332 return success(); 1333 } 1334 1335 /// Add the specified types to the end of the specified type list and return 1336 /// success. This is a helper designed to allow parse methods to be simple 1337 /// and chain through || operators. 1338 ParseResult addTypesToList(ArrayRef<Type> types, 1339 SmallVectorImpl<Type> &result) { 1340 result.append(types.begin(), types.end()); 1341 return success(); 1342 } 1343 1344 /// Parse a dimension list of a tensor or memref type. This populates the 1345 /// dimension list, using ShapedType::kDynamic for the `?` dimensions if 1346 /// `allowDynamic` is set and errors out on `?` otherwise. Parsing the 1347 /// trailing `x` is configurable. 1348 /// 1349 /// dimension-list ::= eps | dimension (`x` dimension)* 1350 /// dimension-list-with-trailing-x ::= (dimension `x`)* 1351 /// dimension ::= `?` | decimal-literal 1352 /// 1353 /// When `allowDynamic` is not set, this is used to parse: 1354 /// 1355 /// static-dimension-list ::= eps | decimal-literal (`x` decimal-literal)* 1356 /// static-dimension-list-with-trailing-x ::= (dimension `x`)* 1357 virtual ParseResult parseDimensionList(SmallVectorImpl<int64_t> &dimensions, 1358 bool allowDynamic = true, 1359 bool withTrailingX = true) = 0; 1360 1361 /// Parse an 'x' token in a dimension list, handling the case where the x is 1362 /// juxtaposed with an element type, as in "xf32", leaving the "f32" as the 1363 /// next token. 1364 virtual ParseResult parseXInDimensionList() = 0; 1365 1366 /// Class used to automatically end a cyclic region on destruction. 1367 class CyclicParseReset { 1368 public: 1369 explicit CyclicParseReset(AsmParser *parser) : parser(parser) {} 1370 1371 ~CyclicParseReset() { 1372 if (parser) 1373 parser->popCyclicParsing(); 1374 } 1375 1376 CyclicParseReset(const CyclicParseReset &) = delete; 1377 CyclicParseReset &operator=(const CyclicParseReset &) = delete; 1378 CyclicParseReset(CyclicParseReset &&rhs) 1379 : parser(std::exchange(rhs.parser, nullptr)) {} 1380 CyclicParseReset &operator=(CyclicParseReset &&rhs) { 1381 parser = std::exchange(rhs.parser, nullptr); 1382 return *this; 1383 } 1384 1385 private: 1386 AsmParser *parser; 1387 }; 1388 1389 /// Attempts to start a cyclic parsing region for `attrOrType`. 1390 /// A cyclic parsing region starts with this call and ends with the 1391 /// destruction of the returned `CyclicParseReset`. During this time, 1392 /// calling `tryStartCyclicParse` with the same attribute in any parser 1393 /// will lead to returning failure. 1394 /// 1395 /// This makes it possible to parse cyclic attributes or types by parsing a 1396 /// short from if nested within itself. 1397 template <class AttrOrTypeT> 1398 FailureOr<CyclicParseReset> tryStartCyclicParse(AttrOrTypeT attrOrType) { 1399 static_assert( 1400 std::is_base_of_v<AttributeTrait::IsMutable<AttrOrTypeT>, 1401 AttrOrTypeT> || 1402 std::is_base_of_v<TypeTrait::IsMutable<AttrOrTypeT>, AttrOrTypeT>, 1403 "Only mutable attributes or types can be cyclic"); 1404 if (failed(pushCyclicParsing(attrOrType.getAsOpaquePointer()))) 1405 return failure(); 1406 1407 return CyclicParseReset(this); 1408 } 1409 1410 protected: 1411 /// Parse a handle to a resource within the assembly format for the given 1412 /// dialect. 1413 virtual FailureOr<AsmDialectResourceHandle> 1414 parseResourceHandle(Dialect *dialect) = 0; 1415 1416 /// Pushes a new attribute or type in the form of a type erased pointer 1417 /// into an internal set. 1418 /// Returns success if the type or attribute was inserted in the set or 1419 /// failure if it was already contained. 1420 virtual LogicalResult pushCyclicParsing(const void *opaquePointer) = 0; 1421 1422 /// Removes the element that was last inserted with a successful call to 1423 /// `pushCyclicParsing`. There must be exactly one `popCyclicParsing` call 1424 /// in reverse order of all successful `pushCyclicParsing`. 1425 virtual void popCyclicParsing() = 0; 1426 1427 //===--------------------------------------------------------------------===// 1428 // Code Completion 1429 //===--------------------------------------------------------------------===// 1430 1431 /// Parse a keyword, or an empty string if the current location signals a code 1432 /// completion. 1433 virtual ParseResult parseKeywordOrCompletion(StringRef *keyword) = 0; 1434 1435 /// Signal the code completion of a set of expected tokens. 1436 virtual void codeCompleteExpectedTokens(ArrayRef<StringRef> tokens) = 0; 1437 1438 private: 1439 AsmParser(const AsmParser &) = delete; 1440 void operator=(const AsmParser &) = delete; 1441 }; 1442 1443 //===----------------------------------------------------------------------===// 1444 // OpAsmParser 1445 //===----------------------------------------------------------------------===// 1446 1447 /// The OpAsmParser has methods for interacting with the asm parser: parsing 1448 /// things from it, emitting errors etc. It has an intentionally high-level API 1449 /// that is designed to reduce/constrain syntax innovation in individual 1450 /// operations. 1451 /// 1452 /// For example, consider an op like this: 1453 /// 1454 /// %x = load %p[%1, %2] : memref<...> 1455 /// 1456 /// The "%x = load" tokens are already parsed and therefore invisible to the 1457 /// custom op parser. This can be supported by calling `parseOperandList` to 1458 /// parse the %p, then calling `parseOperandList` with a `SquareDelimiter` to 1459 /// parse the indices, then calling `parseColonTypeList` to parse the result 1460 /// type. 1461 /// 1462 class OpAsmParser : public AsmParser { 1463 public: 1464 using AsmParser::AsmParser; 1465 ~OpAsmParser() override; 1466 1467 /// Parse a loc(...) specifier if present, filling in result if so. 1468 /// Location for BlockArgument and Operation may be deferred with an alias, in 1469 /// which case an OpaqueLoc is set and will be resolved when parsing 1470 /// completes. 1471 virtual ParseResult 1472 parseOptionalLocationSpecifier(std::optional<Location> &result) = 0; 1473 1474 /// Return the name of the specified result in the specified syntax, as well 1475 /// as the sub-element in the name. It returns an empty string and ~0U for 1476 /// invalid result numbers. For example, in this operation: 1477 /// 1478 /// %x, %y:2, %z = foo.op 1479 /// 1480 /// getResultName(0) == {"x", 0 } 1481 /// getResultName(1) == {"y", 0 } 1482 /// getResultName(2) == {"y", 1 } 1483 /// getResultName(3) == {"z", 0 } 1484 /// getResultName(4) == {"", ~0U } 1485 virtual std::pair<StringRef, unsigned> 1486 getResultName(unsigned resultNo) const = 0; 1487 1488 /// Return the number of declared SSA results. This returns 4 for the foo.op 1489 /// example in the comment for `getResultName`. 1490 virtual size_t getNumResults() const = 0; 1491 1492 // These methods emit an error and return failure or success. This allows 1493 // these to be chained together into a linear sequence of || expressions in 1494 // many cases. 1495 1496 /// Parse an operation in its generic form. 1497 /// The parsed operation is parsed in the current context and inserted in the 1498 /// provided block and insertion point. The results produced by this operation 1499 /// aren't mapped to any named value in the parser. Returns nullptr on 1500 /// failure. 1501 virtual Operation *parseGenericOperation(Block *insertBlock, 1502 Block::iterator insertPt) = 0; 1503 1504 /// Parse the name of an operation, in the custom form. On success, return a 1505 /// an object of type 'OperationName'. Otherwise, failure is returned. 1506 virtual FailureOr<OperationName> parseCustomOperationName() = 0; 1507 1508 //===--------------------------------------------------------------------===// 1509 // Operand Parsing 1510 //===--------------------------------------------------------------------===// 1511 1512 /// This is the representation of an operand reference. 1513 struct UnresolvedOperand { 1514 SMLoc location; // Location of the token. 1515 StringRef name; // Value name, e.g. %42 or %abc 1516 unsigned number; // Number, e.g. 12 for an operand like %xyz#12 1517 }; 1518 1519 /// Parse different components, viz., use-info of operand(s), successor(s), 1520 /// region(s), attribute(s) and function-type, of the generic form of an 1521 /// operation instance and populate the input operation-state 'result' with 1522 /// those components. If any of the components is explicitly provided, then 1523 /// skip parsing that component. 1524 virtual ParseResult parseGenericOperationAfterOpName( 1525 OperationState &result, 1526 std::optional<ArrayRef<UnresolvedOperand>> parsedOperandType = 1527 std::nullopt, 1528 std::optional<ArrayRef<Block *>> parsedSuccessors = std::nullopt, 1529 std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions = 1530 std::nullopt, 1531 std::optional<ArrayRef<NamedAttribute>> parsedAttributes = std::nullopt, 1532 std::optional<Attribute> parsedPropertiesAttribute = std::nullopt, 1533 std::optional<FunctionType> parsedFnType = std::nullopt) = 0; 1534 1535 /// Parse a single SSA value operand name along with a result number if 1536 /// `allowResultNumber` is true. 1537 virtual ParseResult parseOperand(UnresolvedOperand &result, 1538 bool allowResultNumber = true) = 0; 1539 1540 /// Parse a single operand if present. 1541 virtual OptionalParseResult 1542 parseOptionalOperand(UnresolvedOperand &result, 1543 bool allowResultNumber = true) = 0; 1544 1545 /// Parse zero or more SSA comma-separated operand references with a specified 1546 /// surrounding delimiter, and an optional required operand count. 1547 virtual ParseResult 1548 parseOperandList(SmallVectorImpl<UnresolvedOperand> &result, 1549 Delimiter delimiter = Delimiter::None, 1550 bool allowResultNumber = true, 1551 int requiredOperandCount = -1) = 0; 1552 1553 /// Parse a specified number of comma separated operands. 1554 ParseResult parseOperandList(SmallVectorImpl<UnresolvedOperand> &result, 1555 int requiredOperandCount, 1556 Delimiter delimiter = Delimiter::None) { 1557 return parseOperandList(result, delimiter, 1558 /*allowResultNumber=*/true, requiredOperandCount); 1559 } 1560 1561 /// Parse zero or more trailing SSA comma-separated trailing operand 1562 /// references with a specified surrounding delimiter, and an optional 1563 /// required operand count. A leading comma is expected before the 1564 /// operands. 1565 ParseResult 1566 parseTrailingOperandList(SmallVectorImpl<UnresolvedOperand> &result, 1567 Delimiter delimiter = Delimiter::None) { 1568 if (failed(parseOptionalComma())) 1569 return success(); // The comma is optional. 1570 return parseOperandList(result, delimiter); 1571 } 1572 1573 /// Resolve an operand to an SSA value, emitting an error on failure. 1574 virtual ParseResult resolveOperand(const UnresolvedOperand &operand, 1575 Type type, 1576 SmallVectorImpl<Value> &result) = 0; 1577 1578 /// Resolve a list of operands to SSA values, emitting an error on failure, or 1579 /// appending the results to the list on success. This method should be used 1580 /// when all operands have the same type. 1581 template <typename Operands = ArrayRef<UnresolvedOperand>> 1582 ParseResult resolveOperands(Operands &&operands, Type type, 1583 SmallVectorImpl<Value> &result) { 1584 for (const UnresolvedOperand &operand : operands) 1585 if (resolveOperand(operand, type, result)) 1586 return failure(); 1587 return success(); 1588 } 1589 template <typename Operands = ArrayRef<UnresolvedOperand>> 1590 ParseResult resolveOperands(Operands &&operands, Type type, SMLoc loc, 1591 SmallVectorImpl<Value> &result) { 1592 return resolveOperands(std::forward<Operands>(operands), type, result); 1593 } 1594 1595 /// Resolve a list of operands and a list of operand types to SSA values, 1596 /// emitting an error and returning failure, or appending the results 1597 /// to the list on success. 1598 template <typename Operands = ArrayRef<UnresolvedOperand>, 1599 typename Types = ArrayRef<Type>> 1600 std::enable_if_t<!std::is_convertible<Types, Type>::value, ParseResult> 1601 resolveOperands(Operands &&operands, Types &&types, SMLoc loc, 1602 SmallVectorImpl<Value> &result) { 1603 size_t operandSize = llvm::range_size(operands); 1604 size_t typeSize = llvm::range_size(types); 1605 if (operandSize != typeSize) 1606 return emitError(loc) 1607 << "number of operands and types do not match: got " << operandSize 1608 << " operands and " << typeSize << " types"; 1609 1610 for (auto [operand, type] : llvm::zip_equal(operands, types)) 1611 if (resolveOperand(operand, type, result)) 1612 return failure(); 1613 return success(); 1614 } 1615 1616 /// Parses an affine map attribute where dims and symbols are SSA operands. 1617 /// Operand values must come from single-result sources, and be valid 1618 /// dimensions/symbol identifiers according to mlir::isValidDim/Symbol. 1619 virtual ParseResult 1620 parseAffineMapOfSSAIds(SmallVectorImpl<UnresolvedOperand> &operands, 1621 Attribute &map, StringRef attrName, 1622 NamedAttrList &attrs, 1623 Delimiter delimiter = Delimiter::Square) = 0; 1624 1625 /// Parses an affine expression where dims and symbols are SSA operands. 1626 /// Operand values must come from single-result sources, and be valid 1627 /// dimensions/symbol identifiers according to mlir::isValidDim/Symbol. 1628 virtual ParseResult 1629 parseAffineExprOfSSAIds(SmallVectorImpl<UnresolvedOperand> &dimOperands, 1630 SmallVectorImpl<UnresolvedOperand> &symbOperands, 1631 AffineExpr &expr) = 0; 1632 1633 //===--------------------------------------------------------------------===// 1634 // Argument Parsing 1635 //===--------------------------------------------------------------------===// 1636 1637 struct Argument { 1638 UnresolvedOperand ssaName; // SourceLoc, SSA name, result #. 1639 Type type; // Type. 1640 DictionaryAttr attrs; // Attributes if present. 1641 std::optional<Location> sourceLoc; // Source location specifier if present. 1642 }; 1643 1644 /// Parse a single argument with the following syntax: 1645 /// 1646 /// `%ssaName : !type { optionalAttrDict} loc(optionalSourceLoc)` 1647 /// 1648 /// If `allowType` is false or `allowAttrs` are false then the respective 1649 /// parts of the grammar are not parsed. 1650 virtual ParseResult parseArgument(Argument &result, bool allowType = false, 1651 bool allowAttrs = false) = 0; 1652 1653 /// Parse a single argument if present. 1654 virtual OptionalParseResult 1655 parseOptionalArgument(Argument &result, bool allowType = false, 1656 bool allowAttrs = false) = 0; 1657 1658 /// Parse zero or more arguments with a specified surrounding delimiter. 1659 virtual ParseResult parseArgumentList(SmallVectorImpl<Argument> &result, 1660 Delimiter delimiter = Delimiter::None, 1661 bool allowType = false, 1662 bool allowAttrs = false) = 0; 1663 1664 //===--------------------------------------------------------------------===// 1665 // Region Parsing 1666 //===--------------------------------------------------------------------===// 1667 1668 /// Parses a region. Any parsed blocks are appended to 'region' and must be 1669 /// moved to the op regions after the op is created. The first block of the 1670 /// region takes 'arguments'. 1671 /// 1672 /// If 'enableNameShadowing' is set to true, the argument names are allowed to 1673 /// shadow the names of other existing SSA values defined above the region 1674 /// scope. 'enableNameShadowing' can only be set to true for regions attached 1675 /// to operations that are 'IsolatedFromAbove'. 1676 virtual ParseResult parseRegion(Region ®ion, 1677 ArrayRef<Argument> arguments = {}, 1678 bool enableNameShadowing = false) = 0; 1679 1680 /// Parses a region if present. 1681 virtual OptionalParseResult 1682 parseOptionalRegion(Region ®ion, ArrayRef<Argument> arguments = {}, 1683 bool enableNameShadowing = false) = 0; 1684 1685 /// Parses a region if present. If the region is present, a new region is 1686 /// allocated and placed in `region`. If no region is present or on failure, 1687 /// `region` remains untouched. 1688 virtual OptionalParseResult 1689 parseOptionalRegion(std::unique_ptr<Region> ®ion, 1690 ArrayRef<Argument> arguments = {}, 1691 bool enableNameShadowing = false) = 0; 1692 1693 //===--------------------------------------------------------------------===// 1694 // Successor Parsing 1695 //===--------------------------------------------------------------------===// 1696 1697 /// Parse a single operation successor. 1698 virtual ParseResult parseSuccessor(Block *&dest) = 0; 1699 1700 /// Parse an optional operation successor. 1701 virtual OptionalParseResult parseOptionalSuccessor(Block *&dest) = 0; 1702 1703 /// Parse a single operation successor and its operand list. 1704 virtual ParseResult 1705 parseSuccessorAndUseList(Block *&dest, SmallVectorImpl<Value> &operands) = 0; 1706 1707 //===--------------------------------------------------------------------===// 1708 // Type Parsing 1709 //===--------------------------------------------------------------------===// 1710 1711 /// Parse a list of assignments of the form 1712 /// (%x1 = %y1, %x2 = %y2, ...) 1713 ParseResult parseAssignmentList(SmallVectorImpl<Argument> &lhs, 1714 SmallVectorImpl<UnresolvedOperand> &rhs) { 1715 OptionalParseResult result = parseOptionalAssignmentList(lhs, rhs); 1716 if (!result.has_value()) 1717 return emitError(getCurrentLocation(), "expected '('"); 1718 return result.value(); 1719 } 1720 1721 virtual OptionalParseResult 1722 parseOptionalAssignmentList(SmallVectorImpl<Argument> &lhs, 1723 SmallVectorImpl<UnresolvedOperand> &rhs) = 0; 1724 }; 1725 1726 //===--------------------------------------------------------------------===// 1727 // Dialect OpAsm interface. 1728 //===--------------------------------------------------------------------===// 1729 1730 /// A functor used to set the name of the result. See 'getAsmResultNames' below 1731 /// for more details. 1732 using OpAsmSetNameFn = function_ref<void(StringRef)>; 1733 1734 /// A functor used to set the name of the start of a result group of an 1735 /// operation. See 'getAsmResultNames' below for more details. 1736 using OpAsmSetValueNameFn = function_ref<void(Value, StringRef)>; 1737 1738 /// A functor used to set the name of blocks in regions directly nested under 1739 /// an operation. 1740 using OpAsmSetBlockNameFn = function_ref<void(Block *, StringRef)>; 1741 1742 class OpAsmDialectInterface 1743 : public DialectInterface::Base<OpAsmDialectInterface> { 1744 public: 1745 OpAsmDialectInterface(Dialect *dialect) : Base(dialect) {} 1746 1747 //===------------------------------------------------------------------===// 1748 // Aliases 1749 //===------------------------------------------------------------------===// 1750 1751 /// Holds the result of `getAlias` hook call. 1752 enum class AliasResult { 1753 /// The object (type or attribute) is not supported by the hook 1754 /// and an alias was not provided. 1755 NoAlias, 1756 /// An alias was provided, but it might be overriden by other hook. 1757 OverridableAlias, 1758 /// An alias was provided and it should be used 1759 /// (no other hooks will be checked). 1760 FinalAlias 1761 }; 1762 1763 /// Hooks for getting an alias identifier alias for a given symbol, that is 1764 /// not necessarily a part of this dialect. The identifier is used in place of 1765 /// the symbol when printing textual IR. These aliases must not contain `.` or 1766 /// end with a numeric digit([0-9]+). 1767 virtual AliasResult getAlias(Attribute attr, raw_ostream &os) const { 1768 return AliasResult::NoAlias; 1769 } 1770 virtual AliasResult getAlias(Type type, raw_ostream &os) const { 1771 return AliasResult::NoAlias; 1772 } 1773 1774 //===--------------------------------------------------------------------===// 1775 // Resources 1776 //===--------------------------------------------------------------------===// 1777 1778 /// Declare a resource with the given key, returning a handle to use for any 1779 /// references of this resource key within the IR during parsing. The result 1780 /// of `getResourceKey` on the returned handle is permitted to be different 1781 /// than `key`. 1782 virtual FailureOr<AsmDialectResourceHandle> 1783 declareResource(StringRef key) const { 1784 return failure(); 1785 } 1786 1787 /// Return a key to use for the given resource. This key should uniquely 1788 /// identify this resource within the dialect. 1789 virtual std::string 1790 getResourceKey(const AsmDialectResourceHandle &handle) const { 1791 llvm_unreachable( 1792 "Dialect must implement `getResourceKey` when defining resources"); 1793 } 1794 1795 /// Hook for parsing resource entries. Returns failure if the entry was not 1796 /// valid, or could otherwise not be processed correctly. Any necessary errors 1797 /// can be emitted via the provided entry. 1798 virtual LogicalResult parseResource(AsmParsedResourceEntry &entry) const; 1799 1800 /// Hook for building resources to use during printing. The given `op` may be 1801 /// inspected to help determine what information to include. 1802 /// `referencedResources` contains all of the resources detected when printing 1803 /// 'op'. 1804 virtual void 1805 buildResources(Operation *op, 1806 const SetVector<AsmDialectResourceHandle> &referencedResources, 1807 AsmResourceBuilder &builder) const {} 1808 }; 1809 1810 //===--------------------------------------------------------------------===// 1811 // Custom printers and parsers. 1812 //===--------------------------------------------------------------------===// 1813 1814 // Handles custom<DimensionList>(...) in TableGen. 1815 void printDimensionList(OpAsmPrinter &printer, Operation *op, 1816 ArrayRef<int64_t> dimensions); 1817 ParseResult parseDimensionList(OpAsmParser &parser, 1818 DenseI64ArrayAttr &dimensions); 1819 1820 } // namespace mlir 1821 1822 //===--------------------------------------------------------------------===// 1823 // Operation OpAsm interface. 1824 //===--------------------------------------------------------------------===// 1825 1826 /// The OpAsmOpInterface, see OpAsmInterface.td for more details. 1827 #include "mlir/IR/OpAsmOpInterface.h.inc" 1828 #include "mlir/IR/OpAsmTypeInterface.h.inc" 1829 1830 namespace llvm { 1831 template <> 1832 struct DenseMapInfo<mlir::AsmDialectResourceHandle> { 1833 static inline mlir::AsmDialectResourceHandle getEmptyKey() { 1834 return {DenseMapInfo<void *>::getEmptyKey(), 1835 DenseMapInfo<mlir::TypeID>::getEmptyKey(), nullptr}; 1836 } 1837 static inline mlir::AsmDialectResourceHandle getTombstoneKey() { 1838 return {DenseMapInfo<void *>::getTombstoneKey(), 1839 DenseMapInfo<mlir::TypeID>::getTombstoneKey(), nullptr}; 1840 } 1841 static unsigned getHashValue(const mlir::AsmDialectResourceHandle &handle) { 1842 return DenseMapInfo<void *>::getHashValue(handle.getResource()); 1843 } 1844 static bool isEqual(const mlir::AsmDialectResourceHandle &lhs, 1845 const mlir::AsmDialectResourceHandle &rhs) { 1846 return lhs.getResource() == rhs.getResource(); 1847 } 1848 }; 1849 } // namespace llvm 1850 1851 #endif 1852