xref: /llvm-project/mlir/include/mlir/IR/OpImplementation.h (revision 3c64f86314fbf9a3cd578419f16e621a4de57eaa)
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 &param) {
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 &region, 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 &region,
1677                                   ArrayRef<Argument> arguments = {},
1678                                   bool enableNameShadowing = false) = 0;
1679 
1680   /// Parses a region if present.
1681   virtual OptionalParseResult
1682   parseOptionalRegion(Region &region, 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> &region,
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