MLIR  20.0.0git
AsmPrinter.cpp
Go to the documentation of this file.
1 //===- AsmPrinter.cpp - MLIR Assembly Printer Implementation --------------===//
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 file implements the MLIR AsmPrinter class, which is used to implement
10 // the various print() methods on the core IR objects.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "mlir/IR/AffineExpr.h"
15 #include "mlir/IR/AffineMap.h"
16 #include "mlir/IR/AsmState.h"
17 #include "mlir/IR/Attributes.h"
18 #include "mlir/IR/Builders.h"
20 #include "mlir/IR/BuiltinDialect.h"
22 #include "mlir/IR/BuiltinTypes.h"
23 #include "mlir/IR/Dialect.h"
26 #include "mlir/IR/IntegerSet.h"
27 #include "mlir/IR/MLIRContext.h"
29 #include "mlir/IR/Operation.h"
30 #include "mlir/IR/Verifier.h"
31 #include "llvm/ADT/APFloat.h"
32 #include "llvm/ADT/ArrayRef.h"
33 #include "llvm/ADT/DenseMap.h"
34 #include "llvm/ADT/MapVector.h"
35 #include "llvm/ADT/STLExtras.h"
36 #include "llvm/ADT/ScopeExit.h"
37 #include "llvm/ADT/ScopedHashTable.h"
38 #include "llvm/ADT/SetVector.h"
39 #include "llvm/ADT/SmallString.h"
40 #include "llvm/ADT/StringExtras.h"
41 #include "llvm/ADT/StringSet.h"
42 #include "llvm/ADT/TypeSwitch.h"
43 #include "llvm/Support/CommandLine.h"
44 #include "llvm/Support/Debug.h"
45 #include "llvm/Support/Endian.h"
46 #include "llvm/Support/ManagedStatic.h"
47 #include "llvm/Support/Regex.h"
48 #include "llvm/Support/SaveAndRestore.h"
49 #include "llvm/Support/Threading.h"
50 #include "llvm/Support/raw_ostream.h"
51 #include <type_traits>
52 
53 #include <optional>
54 #include <tuple>
55 
56 using namespace mlir;
57 using namespace mlir::detail;
58 
59 #define DEBUG_TYPE "mlir-asm-printer"
60 
61 void OperationName::print(raw_ostream &os) const { os << getStringRef(); }
62 
63 void OperationName::dump() const { print(llvm::errs()); }
64 
65 //===--------------------------------------------------------------------===//
66 // AsmParser
67 //===--------------------------------------------------------------------===//
68 
69 AsmParser::~AsmParser() = default;
71 OpAsmParser::~OpAsmParser() = default;
72 
73 MLIRContext *AsmParser::getContext() const { return getBuilder().getContext(); }
74 
75 /// Parse a type list.
76 /// This is out-of-line to work-around https://github.com/llvm/llvm-project/issues/62918
79  [&]() { return parseType(result.emplace_back()); });
80 }
81 
82 //===----------------------------------------------------------------------===//
83 // DialectAsmPrinter
84 //===----------------------------------------------------------------------===//
85 
87 
88 //===----------------------------------------------------------------------===//
89 // OpAsmPrinter
90 //===----------------------------------------------------------------------===//
91 
92 OpAsmPrinter::~OpAsmPrinter() = default;
93 
95  auto &os = getStream();
96  os << '(';
97  llvm::interleaveComma(op->getOperands(), os, [&](Value operand) {
98  // Print the types of null values as <<NULL TYPE>>.
99  *this << (operand ? operand.getType() : Type());
100  });
101  os << ") -> ";
102 
103  // Print the result list. We don't parenthesize single result types unless
104  // it is a function (avoiding a grammar ambiguity).
105  bool wrapped = op->getNumResults() != 1;
106  if (!wrapped && op->getResult(0).getType() &&
107  llvm::isa<FunctionType>(op->getResult(0).getType()))
108  wrapped = true;
109 
110  if (wrapped)
111  os << '(';
112 
113  llvm::interleaveComma(op->getResults(), os, [&](const OpResult &result) {
114  // Print the types of null values as <<NULL TYPE>>.
115  *this << (result ? result.getType() : Type());
116  });
117 
118  if (wrapped)
119  os << ')';
120 }
121 
122 //===----------------------------------------------------------------------===//
123 // Operation OpAsm interface.
124 //===----------------------------------------------------------------------===//
125 
126 /// The OpAsmOpInterface, see OpAsmInterface.td for more details.
127 #include "mlir/IR/OpAsmInterface.cpp.inc"
128 
129 LogicalResult
131  return entry.emitError() << "unknown 'resource' key '" << entry.getKey()
132  << "' for dialect '" << getDialect()->getNamespace()
133  << "'";
134 }
135 
136 //===----------------------------------------------------------------------===//
137 // OpPrintingFlags
138 //===----------------------------------------------------------------------===//
139 
140 namespace {
141 /// This struct contains command line options that can be used to initialize
142 /// various bits of the AsmPrinter. This uses a struct wrapper to avoid the need
143 /// for global command line options.
144 struct AsmPrinterOptions {
145  llvm::cl::opt<int64_t> printElementsAttrWithHexIfLarger{
146  "mlir-print-elementsattrs-with-hex-if-larger",
147  llvm::cl::desc(
148  "Print DenseElementsAttrs with a hex string that have "
149  "more elements than the given upper limit (use -1 to disable)")};
150 
151  llvm::cl::opt<unsigned> elideElementsAttrIfLarger{
152  "mlir-elide-elementsattrs-if-larger",
153  llvm::cl::desc("Elide ElementsAttrs with \"...\" that have "
154  "more elements than the given upper limit")};
155 
156  llvm::cl::opt<unsigned> elideResourceStringsIfLarger{
157  "mlir-elide-resource-strings-if-larger",
158  llvm::cl::desc(
159  "Elide printing value of resources if string is too long in chars.")};
160 
161  llvm::cl::opt<bool> printDebugInfoOpt{
162  "mlir-print-debuginfo", llvm::cl::init(false),
163  llvm::cl::desc("Print debug info in MLIR output")};
164 
165  llvm::cl::opt<bool> printPrettyDebugInfoOpt{
166  "mlir-pretty-debuginfo", llvm::cl::init(false),
167  llvm::cl::desc("Print pretty debug info in MLIR output")};
168 
169  // Use the generic op output form in the operation printer even if the custom
170  // form is defined.
171  llvm::cl::opt<bool> printGenericOpFormOpt{
172  "mlir-print-op-generic", llvm::cl::init(false),
173  llvm::cl::desc("Print the generic op form"), llvm::cl::Hidden};
174 
175  llvm::cl::opt<bool> assumeVerifiedOpt{
176  "mlir-print-assume-verified", llvm::cl::init(false),
177  llvm::cl::desc("Skip op verification when using custom printers"),
178  llvm::cl::Hidden};
179 
180  llvm::cl::opt<bool> printLocalScopeOpt{
181  "mlir-print-local-scope", llvm::cl::init(false),
182  llvm::cl::desc("Print with local scope and inline information (eliding "
183  "aliases for attributes, types, and locations")};
184 
185  llvm::cl::opt<bool> skipRegionsOpt{
186  "mlir-print-skip-regions", llvm::cl::init(false),
187  llvm::cl::desc("Skip regions when printing ops.")};
188 
189  llvm::cl::opt<bool> printValueUsers{
190  "mlir-print-value-users", llvm::cl::init(false),
191  llvm::cl::desc(
192  "Print users of operation results and block arguments as a comment")};
193 
194  llvm::cl::opt<bool> printUniqueSSAIDs{
195  "mlir-print-unique-ssa-ids", llvm::cl::init(false),
196  llvm::cl::desc("Print unique SSA ID numbers for values, block arguments "
197  "and naming conflicts across all regions")};
198 };
199 } // namespace
200 
201 static llvm::ManagedStatic<AsmPrinterOptions> clOptions;
202 
203 /// Register a set of useful command-line options that can be used to configure
204 /// various flags within the AsmPrinter.
206  // Make sure that the options struct has been initialized.
207  *clOptions;
208 }
209 
210 /// Initialize the printing flags with default supplied by the cl::opts above.
212  : printDebugInfoFlag(false), printDebugInfoPrettyFormFlag(false),
213  printGenericOpFormFlag(false), skipRegionsFlag(false),
214  assumeVerifiedFlag(false), printLocalScope(false),
215  printValueUsersFlag(false), printUniqueSSAIDsFlag(false) {
216  // Initialize based upon command line options, if they are available.
217  if (!clOptions.isConstructed())
218  return;
219  if (clOptions->elideElementsAttrIfLarger.getNumOccurrences())
220  elementsAttrElementLimit = clOptions->elideElementsAttrIfLarger;
221  if (clOptions->printElementsAttrWithHexIfLarger.getNumOccurrences())
222  elementsAttrHexElementLimit =
223  clOptions->printElementsAttrWithHexIfLarger.getValue();
224  if (clOptions->elideResourceStringsIfLarger.getNumOccurrences())
225  resourceStringCharLimit = clOptions->elideResourceStringsIfLarger;
226  printDebugInfoFlag = clOptions->printDebugInfoOpt;
227  printDebugInfoPrettyFormFlag = clOptions->printPrettyDebugInfoOpt;
228  printGenericOpFormFlag = clOptions->printGenericOpFormOpt;
229  assumeVerifiedFlag = clOptions->assumeVerifiedOpt;
230  printLocalScope = clOptions->printLocalScopeOpt;
231  skipRegionsFlag = clOptions->skipRegionsOpt;
232  printValueUsersFlag = clOptions->printValueUsers;
233  printUniqueSSAIDsFlag = clOptions->printUniqueSSAIDs;
234 }
235 
236 /// Enable the elision of large elements attributes, by printing a '...'
237 /// instead of the element data, when the number of elements is greater than
238 /// `largeElementLimit`. Note: The IR generated with this option is not
239 /// parsable.
241 OpPrintingFlags::elideLargeElementsAttrs(int64_t largeElementLimit) {
242  elementsAttrElementLimit = largeElementLimit;
243  return *this;
244 }
245 
248  elementsAttrHexElementLimit = largeElementLimit;
249  return *this;
250 }
251 
253 OpPrintingFlags::elideLargeResourceString(int64_t largeResourceLimit) {
254  resourceStringCharLimit = largeResourceLimit;
255  return *this;
256 }
257 
258 /// Enable printing of debug information. If 'prettyForm' is set to true,
259 /// debug information is printed in a more readable 'pretty' form.
261  bool prettyForm) {
262  printDebugInfoFlag = enable;
263  printDebugInfoPrettyFormFlag = prettyForm;
264  return *this;
265 }
266 
267 /// Always print operations in the generic form.
269  printGenericOpFormFlag = enable;
270  return *this;
271 }
272 
273 /// Always skip Regions.
275  skipRegionsFlag = skip;
276  return *this;
277 }
278 
279 /// Do not verify the operation when using custom operation printers.
281  assumeVerifiedFlag = true;
282  return *this;
283 }
284 
285 /// Use local scope when printing the operation. This allows for using the
286 /// printer in a more localized and thread-safe setting, but may not necessarily
287 /// be identical of what the IR will look like when dumping the full module.
289  printLocalScope = true;
290  return *this;
291 }
292 
293 /// Print users of values as comments.
295  printValueUsersFlag = true;
296  return *this;
297 }
298 
299 /// Return if the given ElementsAttr should be elided.
300 bool OpPrintingFlags::shouldElideElementsAttr(ElementsAttr attr) const {
301  return elementsAttrElementLimit &&
302  *elementsAttrElementLimit < int64_t(attr.getNumElements()) &&
303  !llvm::isa<SplatElementsAttr>(attr);
304 }
305 
306 /// Return if the given ElementsAttr should be printed as hex string.
307 bool OpPrintingFlags::shouldPrintElementsAttrWithHex(ElementsAttr attr) const {
308  // -1 is used to disable hex printing.
309  return (elementsAttrHexElementLimit != -1) &&
310  (elementsAttrHexElementLimit < int64_t(attr.getNumElements())) &&
311  !llvm::isa<SplatElementsAttr>(attr);
312 }
313 
314 /// Return the size limit for printing large ElementsAttr.
315 std::optional<int64_t> OpPrintingFlags::getLargeElementsAttrLimit() const {
316  return elementsAttrElementLimit;
317 }
318 
319 /// Return the size limit for printing large ElementsAttr as hex string.
321  return elementsAttrHexElementLimit;
322 }
323 
324 /// Return the size limit for printing large ElementsAttr.
325 std::optional<uint64_t> OpPrintingFlags::getLargeResourceStringLimit() const {
326  return resourceStringCharLimit;
327 }
328 
329 /// Return if debug information should be printed.
331  return printDebugInfoFlag;
332 }
333 
334 /// Return if debug information should be printed in the pretty form.
336  return printDebugInfoPrettyFormFlag;
337 }
338 
339 /// Return if operations should be printed in the generic form.
341  return printGenericOpFormFlag;
342 }
343 
344 /// Return if Region should be skipped.
345 bool OpPrintingFlags::shouldSkipRegions() const { return skipRegionsFlag; }
346 
347 /// Return if operation verification should be skipped.
349  return assumeVerifiedFlag;
350 }
351 
352 /// Return if the printer should use local scope when dumping the IR.
353 bool OpPrintingFlags::shouldUseLocalScope() const { return printLocalScope; }
354 
355 /// Return if the printer should print users of values.
357  return printValueUsersFlag;
358 }
359 
360 /// Return if the printer should use unique IDs.
362  return printUniqueSSAIDsFlag || shouldPrintGenericOpForm();
363 }
364 
365 //===----------------------------------------------------------------------===//
366 // NewLineCounter
367 //===----------------------------------------------------------------------===//
368 
369 namespace {
370 /// This class is a simple formatter that emits a new line when inputted into a
371 /// stream, that enables counting the number of newlines emitted. This class
372 /// should be used whenever emitting newlines in the printer.
373 struct NewLineCounter {
374  unsigned curLine = 1;
375 };
376 
377 static raw_ostream &operator<<(raw_ostream &os, NewLineCounter &newLine) {
378  ++newLine.curLine;
379  return os << '\n';
380 }
381 } // namespace
382 
383 //===----------------------------------------------------------------------===//
384 // AsmPrinter::Impl
385 //===----------------------------------------------------------------------===//
386 
387 namespace mlir {
389 public:
390  Impl(raw_ostream &os, AsmStateImpl &state);
391  explicit Impl(Impl &other) : Impl(other.os, other.state) {}
392 
393  /// Returns the output stream of the printer.
394  raw_ostream &getStream() { return os; }
395 
396  template <typename Container, typename UnaryFunctor>
397  inline void interleaveComma(const Container &c, UnaryFunctor eachFn) const {
398  llvm::interleaveComma(c, os, eachFn);
399  }
400 
401  /// This enum describes the different kinds of elision for the type of an
402  /// attribute when printing it.
403  enum class AttrTypeElision {
404  /// The type must not be elided,
405  Never,
406  /// The type may be elided when it matches the default used in the parser
407  /// (for example i64 is the default for integer attributes).
408  May,
409  /// The type must be elided.
410  Must
411  };
412 
413  /// Print the given attribute or an alias.
414  void printAttribute(Attribute attr,
416  /// Print the given attribute without considering an alias.
417  void printAttributeImpl(Attribute attr,
419 
420  /// Print the alias for the given attribute, return failure if no alias could
421  /// be printed.
422  LogicalResult printAlias(Attribute attr);
423 
424  /// Print the given type or an alias.
425  void printType(Type type);
426  /// Print the given type.
427  void printTypeImpl(Type type);
428 
429  /// Print the alias for the given type, return failure if no alias could
430  /// be printed.
431  LogicalResult printAlias(Type type);
432 
433  /// Print the given location to the stream. If `allowAlias` is true, this
434  /// allows for the internal location to use an attribute alias.
435  void printLocation(LocationAttr loc, bool allowAlias = false);
436 
437  /// Print a reference to the given resource that is owned by the given
438  /// dialect.
439  void printResourceHandle(const AsmDialectResourceHandle &resource);
440 
441  void printAffineMap(AffineMap map);
442  void
444  function_ref<void(unsigned, bool)> printValueName = nullptr);
445  void printAffineConstraint(AffineExpr expr, bool isEq);
446  void printIntegerSet(IntegerSet set);
447 
448  LogicalResult pushCyclicPrinting(const void *opaquePointer);
449 
450  void popCyclicPrinting();
451 
453 
454 protected:
456  ArrayRef<StringRef> elidedAttrs = {},
457  bool withKeyword = false);
459  void printTrailingLocation(Location loc, bool allowAlias = true);
460  void printLocationInternal(LocationAttr loc, bool pretty = false,
461  bool isTopLevel = false);
462 
463  /// Print a dense elements attribute. If 'allowHex' is true, a hex string is
464  /// used instead of individual elements when the elements attr is large.
465  void printDenseElementsAttr(DenseElementsAttr attr, bool allowHex);
466 
467  /// Print a dense string elements attribute.
468  void printDenseStringElementsAttr(DenseStringElementsAttr attr);
469 
470  /// Print a dense elements attribute. If 'allowHex' is true, a hex string is
471  /// used instead of individual elements when the elements attr is large.
473  bool allowHex);
474 
475  /// Print a dense array attribute.
476  void printDenseArrayAttr(DenseArrayAttr attr);
477 
478  void printDialectAttribute(Attribute attr);
479  void printDialectType(Type type);
480 
481  /// Print an escaped string, wrapped with "".
482  void printEscapedString(StringRef str);
483 
484  /// Print a hex string, wrapped with "".
485  void printHexString(StringRef str);
486  void printHexString(ArrayRef<char> data);
487 
488  /// This enum is used to represent the binding strength of the enclosing
489  /// context that an AffineExprStorage is being printed in, so we can
490  /// intelligently produce parens.
491  enum class BindingStrength {
492  Weak, // + and -
493  Strong, // All other binary operators.
494  };
496  AffineExpr expr, BindingStrength enclosingTightness,
497  function_ref<void(unsigned, bool)> printValueName = nullptr);
498 
499  /// The output stream for the printer.
500  raw_ostream &os;
501 
502  /// An underlying assembly printer state.
504 
505  /// A set of flags to control the printer's behavior.
507 
508  /// A tracker for the number of new lines emitted during printing.
509  NewLineCounter newLine;
510 };
511 } // namespace mlir
512 
513 //===----------------------------------------------------------------------===//
514 // AliasInitializer
515 //===----------------------------------------------------------------------===//
516 
517 namespace {
518 /// This class represents a specific instance of a symbol Alias.
519 class SymbolAlias {
520 public:
521  SymbolAlias(StringRef name, uint32_t suffixIndex, bool isType,
522  bool isDeferrable)
523  : name(name), suffixIndex(suffixIndex), isType(isType),
524  isDeferrable(isDeferrable) {}
525 
526  /// Print this alias to the given stream.
527  void print(raw_ostream &os) const {
528  os << (isType ? "!" : "#") << name;
529  if (suffixIndex)
530  os << suffixIndex;
531  }
532 
533  /// Returns true if this is a type alias.
534  bool isTypeAlias() const { return isType; }
535 
536  /// Returns true if this alias supports deferred resolution when parsing.
537  bool canBeDeferred() const { return isDeferrable; }
538 
539 private:
540  /// The main name of the alias.
541  StringRef name;
542  /// The suffix index of the alias.
543  uint32_t suffixIndex : 30;
544  /// A flag indicating whether this alias is for a type.
545  bool isType : 1;
546  /// A flag indicating whether this alias may be deferred or not.
547  bool isDeferrable : 1;
548 };
549 
550 /// This class represents a utility that initializes the set of attribute and
551 /// type aliases, without the need to store the extra information within the
552 /// main AliasState class or pass it around via function arguments.
553 class AliasInitializer {
554 public:
555  AliasInitializer(
557  llvm::BumpPtrAllocator &aliasAllocator)
558  : interfaces(interfaces), aliasAllocator(aliasAllocator),
559  aliasOS(aliasBuffer) {}
560 
561  void initialize(Operation *op, const OpPrintingFlags &printerFlags,
562  llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias);
563 
564  /// Visit the given attribute to see if it has an alias. `canBeDeferred` is
565  /// set to true if the originator of this attribute can resolve the alias
566  /// after parsing has completed (e.g. in the case of operation locations).
567  /// `elideType` indicates if the type of the attribute should be skipped when
568  /// looking for nested aliases. Returns the maximum alias depth of the
569  /// attribute, and the alias index of this attribute.
570  std::pair<size_t, size_t> visit(Attribute attr, bool canBeDeferred = false,
571  bool elideType = false) {
572  return visitImpl(attr, aliases, canBeDeferred, elideType);
573  }
574 
575  /// Visit the given type to see if it has an alias. `canBeDeferred` is
576  /// set to true if the originator of this attribute can resolve the alias
577  /// after parsing has completed. Returns the maximum alias depth of the type,
578  /// and the alias index of this type.
579  std::pair<size_t, size_t> visit(Type type, bool canBeDeferred = false) {
580  return visitImpl(type, aliases, canBeDeferred);
581  }
582 
583 private:
584  struct InProgressAliasInfo {
585  InProgressAliasInfo()
586  : aliasDepth(0), isType(false), canBeDeferred(false) {}
587  InProgressAliasInfo(StringRef alias, bool isType, bool canBeDeferred)
588  : alias(alias), aliasDepth(1), isType(isType),
589  canBeDeferred(canBeDeferred) {}
590 
591  bool operator<(const InProgressAliasInfo &rhs) const {
592  // Order first by depth, then by attr/type kind, and then by name.
593  if (aliasDepth != rhs.aliasDepth)
594  return aliasDepth < rhs.aliasDepth;
595  if (isType != rhs.isType)
596  return isType;
597  return alias < rhs.alias;
598  }
599 
600  /// The alias for the attribute or type, or std::nullopt if the value has no
601  /// alias.
602  std::optional<StringRef> alias;
603  /// The alias depth of this attribute or type, i.e. an indication of the
604  /// relative ordering of when to print this alias.
605  unsigned aliasDepth : 30;
606  /// If this alias represents a type or an attribute.
607  bool isType : 1;
608  /// If this alias can be deferred or not.
609  bool canBeDeferred : 1;
610  /// Indices for child aliases.
611  SmallVector<size_t> childIndices;
612  };
613 
614  /// Visit the given attribute or type to see if it has an alias.
615  /// `canBeDeferred` is set to true if the originator of this value can resolve
616  /// the alias after parsing has completed (e.g. in the case of operation
617  /// locations). Returns the maximum alias depth of the value, and its alias
618  /// index.
619  template <typename T, typename... PrintArgs>
620  std::pair<size_t, size_t>
621  visitImpl(T value,
622  llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
623  bool canBeDeferred, PrintArgs &&...printArgs);
624 
625  /// Mark the given alias as non-deferrable.
626  void markAliasNonDeferrable(size_t aliasIndex);
627 
628  /// Try to generate an alias for the provided symbol. If an alias is
629  /// generated, the provided alias mapping and reverse mapping are updated.
630  template <typename T>
631  void generateAlias(T symbol, InProgressAliasInfo &alias, bool canBeDeferred);
632 
633  /// Given a collection of aliases and symbols, initialize a mapping from a
634  /// symbol to a given alias.
635  static void initializeAliases(
636  llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
637  llvm::MapVector<const void *, SymbolAlias> &symbolToAlias);
638 
639  /// The set of asm interfaces within the context.
641 
642  /// An allocator used for alias names.
643  llvm::BumpPtrAllocator &aliasAllocator;
644 
645  /// The set of built aliases.
646  llvm::MapVector<const void *, InProgressAliasInfo> aliases;
647 
648  /// Storage and stream used when generating an alias.
649  SmallString<32> aliasBuffer;
650  llvm::raw_svector_ostream aliasOS;
651 };
652 
653 /// This class implements a dummy OpAsmPrinter that doesn't print any output,
654 /// and merely collects the attributes and types that *would* be printed in a
655 /// normal print invocation so that we can generate proper aliases. This allows
656 /// for us to generate aliases only for the attributes and types that would be
657 /// in the output, and trims down unnecessary output.
658 class DummyAliasOperationPrinter : private OpAsmPrinter {
659 public:
660  explicit DummyAliasOperationPrinter(const OpPrintingFlags &printerFlags,
661  AliasInitializer &initializer)
662  : printerFlags(printerFlags), initializer(initializer) {}
663 
664  /// Prints the entire operation with the custom assembly form, if available,
665  /// or the generic assembly form, otherwise.
666  void printCustomOrGenericOp(Operation *op) override {
667  // Visit the operation location.
668  if (printerFlags.shouldPrintDebugInfo())
669  initializer.visit(op->getLoc(), /*canBeDeferred=*/true);
670 
671  // If requested, always print the generic form.
672  if (!printerFlags.shouldPrintGenericOpForm()) {
673  op->getName().printAssembly(op, *this, /*defaultDialect=*/"");
674  return;
675  }
676 
677  // Otherwise print with the generic assembly form.
678  printGenericOp(op);
679  }
680 
681 private:
682  /// Print the given operation in the generic form.
683  void printGenericOp(Operation *op, bool printOpName = true) override {
684  // Consider nested operations for aliases.
685  if (!printerFlags.shouldSkipRegions()) {
686  for (Region &region : op->getRegions())
687  printRegion(region, /*printEntryBlockArgs=*/true,
688  /*printBlockTerminators=*/true);
689  }
690 
691  // Visit all the types used in the operation.
692  for (Type type : op->getOperandTypes())
693  printType(type);
694  for (Type type : op->getResultTypes())
695  printType(type);
696 
697  // Consider the attributes of the operation for aliases.
698  for (const NamedAttribute &attr : op->getAttrs())
699  printAttribute(attr.getValue());
700  }
701 
702  /// Print the given block. If 'printBlockArgs' is false, the arguments of the
703  /// block are not printed. If 'printBlockTerminator' is false, the terminator
704  /// operation of the block is not printed.
705  void print(Block *block, bool printBlockArgs = true,
706  bool printBlockTerminator = true) {
707  // Consider the types of the block arguments for aliases if 'printBlockArgs'
708  // is set to true.
709  if (printBlockArgs) {
710  for (BlockArgument arg : block->getArguments()) {
711  printType(arg.getType());
712 
713  // Visit the argument location.
714  if (printerFlags.shouldPrintDebugInfo())
715  // TODO: Allow deferring argument locations.
716  initializer.visit(arg.getLoc(), /*canBeDeferred=*/false);
717  }
718  }
719 
720  // Consider the operations within this block, ignoring the terminator if
721  // requested.
722  bool hasTerminator =
723  !block->empty() && block->back().hasTrait<OpTrait::IsTerminator>();
724  auto range = llvm::make_range(
725  block->begin(),
726  std::prev(block->end(),
727  (!hasTerminator || printBlockTerminator) ? 0 : 1));
728  for (Operation &op : range)
729  printCustomOrGenericOp(&op);
730  }
731 
732  /// Print the given region.
733  void printRegion(Region &region, bool printEntryBlockArgs,
734  bool printBlockTerminators,
735  bool printEmptyBlock = false) override {
736  if (region.empty())
737  return;
738  if (printerFlags.shouldSkipRegions()) {
739  os << "{...}";
740  return;
741  }
742 
743  auto *entryBlock = &region.front();
744  print(entryBlock, printEntryBlockArgs, printBlockTerminators);
745  for (Block &b : llvm::drop_begin(region, 1))
746  print(&b);
747  }
748 
749  void printRegionArgument(BlockArgument arg, ArrayRef<NamedAttribute> argAttrs,
750  bool omitType) override {
751  printType(arg.getType());
752  // Visit the argument location.
753  if (printerFlags.shouldPrintDebugInfo())
754  // TODO: Allow deferring argument locations.
755  initializer.visit(arg.getLoc(), /*canBeDeferred=*/false);
756  }
757 
758  /// Consider the given type to be printed for an alias.
759  void printType(Type type) override { initializer.visit(type); }
760 
761  /// Consider the given attribute to be printed for an alias.
762  void printAttribute(Attribute attr) override { initializer.visit(attr); }
763  void printAttributeWithoutType(Attribute attr) override {
764  printAttribute(attr);
765  }
766  LogicalResult printAlias(Attribute attr) override {
767  initializer.visit(attr);
768  return success();
769  }
770  LogicalResult printAlias(Type type) override {
771  initializer.visit(type);
772  return success();
773  }
774 
775  /// Consider the given location to be printed for an alias.
776  void printOptionalLocationSpecifier(Location loc) override {
777  printAttribute(loc);
778  }
779 
780  /// Print the given set of attributes with names not included within
781  /// 'elidedAttrs'.
782  void printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
783  ArrayRef<StringRef> elidedAttrs = {}) override {
784  if (attrs.empty())
785  return;
786  if (elidedAttrs.empty()) {
787  for (const NamedAttribute &attr : attrs)
788  printAttribute(attr.getValue());
789  return;
790  }
791  llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
792  elidedAttrs.end());
793  for (const NamedAttribute &attr : attrs)
794  if (!elidedAttrsSet.contains(attr.getName().strref()))
795  printAttribute(attr.getValue());
796  }
797  void printOptionalAttrDictWithKeyword(
799  ArrayRef<StringRef> elidedAttrs = {}) override {
800  printOptionalAttrDict(attrs, elidedAttrs);
801  }
802 
803  /// Return a null stream as the output stream, this will ignore any data fed
804  /// to it.
805  raw_ostream &getStream() const override { return os; }
806 
807  /// The following are hooks of `OpAsmPrinter` that are not necessary for
808  /// determining potential aliases.
809  void printFloat(const APFloat &) override {}
810  void printAffineMapOfSSAIds(AffineMapAttr, ValueRange) override {}
811  void printAffineExprOfSSAIds(AffineExpr, ValueRange, ValueRange) override {}
812  void printNewline() override {}
813  void increaseIndent() override {}
814  void decreaseIndent() override {}
815  void printOperand(Value) override {}
816  void printOperand(Value, raw_ostream &os) override {
817  // Users expect the output string to have at least the prefixed % to signal
818  // a value name. To maintain this invariant, emit a name even if it is
819  // guaranteed to go unused.
820  os << "%";
821  }
822  void printKeywordOrString(StringRef) override {}
823  void printString(StringRef) override {}
824  void printResourceHandle(const AsmDialectResourceHandle &) override {}
825  void printSymbolName(StringRef) override {}
826  void printSuccessor(Block *) override {}
827  void printSuccessorAndUseList(Block *, ValueRange) override {}
828  void shadowRegionArgs(Region &, ValueRange) override {}
829 
830  /// The printer flags to use when determining potential aliases.
831  const OpPrintingFlags &printerFlags;
832 
833  /// The initializer to use when identifying aliases.
834  AliasInitializer &initializer;
835 
836  /// A dummy output stream.
837  mutable llvm::raw_null_ostream os;
838 };
839 
840 class DummyAliasDialectAsmPrinter : public DialectAsmPrinter {
841 public:
842  explicit DummyAliasDialectAsmPrinter(AliasInitializer &initializer,
843  bool canBeDeferred,
844  SmallVectorImpl<size_t> &childIndices)
845  : initializer(initializer), canBeDeferred(canBeDeferred),
846  childIndices(childIndices) {}
847 
848  /// Print the given attribute/type, visiting any nested aliases that would be
849  /// generated as part of printing. Returns the maximum alias depth found while
850  /// printing the given value.
851  template <typename T, typename... PrintArgs>
852  size_t printAndVisitNestedAliases(T value, PrintArgs &&...printArgs) {
853  printAndVisitNestedAliasesImpl(value, printArgs...);
854  return maxAliasDepth;
855  }
856 
857 private:
858  /// Print the given attribute/type, visiting any nested aliases that would be
859  /// generated as part of printing.
860  void printAndVisitNestedAliasesImpl(Attribute attr, bool elideType) {
861  if (!isa<BuiltinDialect>(attr.getDialect())) {
862  attr.getDialect().printAttribute(attr, *this);
863 
864  // Process the builtin attributes.
865  } else if (llvm::isa<AffineMapAttr, DenseArrayAttr, FloatAttr, IntegerAttr,
866  IntegerSetAttr, UnitAttr>(attr)) {
867  return;
868  } else if (auto distinctAttr = dyn_cast<DistinctAttr>(attr)) {
869  printAttribute(distinctAttr.getReferencedAttr());
870  } else if (auto dictAttr = dyn_cast<DictionaryAttr>(attr)) {
871  for (const NamedAttribute &nestedAttr : dictAttr.getValue()) {
872  printAttribute(nestedAttr.getName());
873  printAttribute(nestedAttr.getValue());
874  }
875  } else if (auto arrayAttr = dyn_cast<ArrayAttr>(attr)) {
876  for (Attribute nestedAttr : arrayAttr.getValue())
877  printAttribute(nestedAttr);
878  } else if (auto typeAttr = dyn_cast<TypeAttr>(attr)) {
879  printType(typeAttr.getValue());
880  } else if (auto locAttr = dyn_cast<OpaqueLoc>(attr)) {
881  printAttribute(locAttr.getFallbackLocation());
882  } else if (auto locAttr = dyn_cast<NameLoc>(attr)) {
883  if (!isa<UnknownLoc>(locAttr.getChildLoc()))
884  printAttribute(locAttr.getChildLoc());
885  } else if (auto locAttr = dyn_cast<CallSiteLoc>(attr)) {
886  printAttribute(locAttr.getCallee());
887  printAttribute(locAttr.getCaller());
888  } else if (auto locAttr = dyn_cast<FusedLoc>(attr)) {
889  if (Attribute metadata = locAttr.getMetadata())
890  printAttribute(metadata);
891  for (Location nestedLoc : locAttr.getLocations())
892  printAttribute(nestedLoc);
893  }
894 
895  // Don't print the type if we must elide it, or if it is a None type.
896  if (!elideType) {
897  if (auto typedAttr = llvm::dyn_cast<TypedAttr>(attr)) {
898  Type attrType = typedAttr.getType();
899  if (!llvm::isa<NoneType>(attrType))
900  printType(attrType);
901  }
902  }
903  }
904  void printAndVisitNestedAliasesImpl(Type type) {
905  if (!isa<BuiltinDialect>(type.getDialect()))
906  return type.getDialect().printType(type, *this);
907 
908  // Only visit the layout of memref if it isn't the identity.
909  if (auto memrefTy = llvm::dyn_cast<MemRefType>(type)) {
910  printType(memrefTy.getElementType());
911  MemRefLayoutAttrInterface layout = memrefTy.getLayout();
912  if (!llvm::isa<AffineMapAttr>(layout) || !layout.isIdentity())
913  printAttribute(memrefTy.getLayout());
914  if (memrefTy.getMemorySpace())
915  printAttribute(memrefTy.getMemorySpace());
916  return;
917  }
918 
919  // For most builtin types, we can simply walk the sub elements.
920  auto visitFn = [&](auto element) {
921  if (element)
922  (void)printAlias(element);
923  };
924  type.walkImmediateSubElements(visitFn, visitFn);
925  }
926 
927  /// Consider the given type to be printed for an alias.
928  void printType(Type type) override {
929  recordAliasResult(initializer.visit(type, canBeDeferred));
930  }
931 
932  /// Consider the given attribute to be printed for an alias.
933  void printAttribute(Attribute attr) override {
934  recordAliasResult(initializer.visit(attr, canBeDeferred));
935  }
936  void printAttributeWithoutType(Attribute attr) override {
937  recordAliasResult(
938  initializer.visit(attr, canBeDeferred, /*elideType=*/true));
939  }
940  LogicalResult printAlias(Attribute attr) override {
941  printAttribute(attr);
942  return success();
943  }
944  LogicalResult printAlias(Type type) override {
945  printType(type);
946  return success();
947  }
948 
949  /// Record the alias result of a child element.
950  void recordAliasResult(std::pair<size_t, size_t> aliasDepthAndIndex) {
951  childIndices.push_back(aliasDepthAndIndex.second);
952  if (aliasDepthAndIndex.first > maxAliasDepth)
953  maxAliasDepth = aliasDepthAndIndex.first;
954  }
955 
956  /// Return a null stream as the output stream, this will ignore any data fed
957  /// to it.
958  raw_ostream &getStream() const override { return os; }
959 
960  /// The following are hooks of `DialectAsmPrinter` that are not necessary for
961  /// determining potential aliases.
962  void printFloat(const APFloat &) override {}
963  void printKeywordOrString(StringRef) override {}
964  void printString(StringRef) override {}
965  void printSymbolName(StringRef) override {}
966  void printResourceHandle(const AsmDialectResourceHandle &) override {}
967 
968  LogicalResult pushCyclicPrinting(const void *opaquePointer) override {
969  return success(cyclicPrintingStack.insert(opaquePointer));
970  }
971 
972  void popCyclicPrinting() override { cyclicPrintingStack.pop_back(); }
973 
974  /// Stack of potentially cyclic mutable attributes or type currently being
975  /// printed.
976  SetVector<const void *> cyclicPrintingStack;
977 
978  /// The initializer to use when identifying aliases.
979  AliasInitializer &initializer;
980 
981  /// If the aliases visited by this printer can be deferred.
982  bool canBeDeferred;
983 
984  /// The indices of child aliases.
985  SmallVectorImpl<size_t> &childIndices;
986 
987  /// The maximum alias depth found by the printer.
988  size_t maxAliasDepth = 0;
989 
990  /// A dummy output stream.
991  mutable llvm::raw_null_ostream os;
992 };
993 } // namespace
994 
995 /// Sanitize the given name such that it can be used as a valid identifier. If
996 /// the string needs to be modified in any way, the provided buffer is used to
997 /// store the new copy,
998 static StringRef sanitizeIdentifier(StringRef name, SmallString<16> &buffer,
999  StringRef allowedPunctChars = "$._-",
1000  bool allowTrailingDigit = true) {
1001  assert(!name.empty() && "Shouldn't have an empty name here");
1002 
1003  auto validChar = [&](char ch) {
1004  return llvm::isAlnum(ch) || allowedPunctChars.contains(ch);
1005  };
1006 
1007  auto copyNameToBuffer = [&] {
1008  for (char ch : name) {
1009  if (validChar(ch))
1010  buffer.push_back(ch);
1011  else if (ch == ' ')
1012  buffer.push_back('_');
1013  else
1014  buffer.append(llvm::utohexstr((unsigned char)ch));
1015  }
1016  };
1017 
1018  // Check to see if this name is valid. If it starts with a digit, then it
1019  // could conflict with the autogenerated numeric ID's, so add an underscore
1020  // prefix to avoid problems.
1021  if (isdigit(name[0]) || (!validChar(name[0]) && name[0] != ' ')) {
1022  buffer.push_back('_');
1023  copyNameToBuffer();
1024  return buffer;
1025  }
1026 
1027  // If the name ends with a trailing digit, add a '_' to avoid potential
1028  // conflicts with autogenerated ID's.
1029  if (!allowTrailingDigit && isdigit(name.back())) {
1030  copyNameToBuffer();
1031  buffer.push_back('_');
1032  return buffer;
1033  }
1034 
1035  // Check to see that the name consists of only valid identifier characters.
1036  for (char ch : name) {
1037  if (!validChar(ch)) {
1038  copyNameToBuffer();
1039  return buffer;
1040  }
1041  }
1042 
1043  // If there are no invalid characters, return the original name.
1044  return name;
1045 }
1046 
1047 /// Given a collection of aliases and symbols, initialize a mapping from a
1048 /// symbol to a given alias.
1049 void AliasInitializer::initializeAliases(
1050  llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
1051  llvm::MapVector<const void *, SymbolAlias> &symbolToAlias) {
1053  unprocessedAliases = visitedSymbols.takeVector();
1054  llvm::stable_sort(unprocessedAliases, [](const auto &lhs, const auto &rhs) {
1055  return lhs.second < rhs.second;
1056  });
1057 
1058  llvm::StringMap<unsigned> nameCounts;
1059  for (auto &[symbol, aliasInfo] : unprocessedAliases) {
1060  if (!aliasInfo.alias)
1061  continue;
1062  StringRef alias = *aliasInfo.alias;
1063  unsigned nameIndex = nameCounts[alias]++;
1064  symbolToAlias.insert(
1065  {symbol, SymbolAlias(alias, nameIndex, aliasInfo.isType,
1066  aliasInfo.canBeDeferred)});
1067  }
1068 }
1069 
1070 void AliasInitializer::initialize(
1071  Operation *op, const OpPrintingFlags &printerFlags,
1072  llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias) {
1073  // Use a dummy printer when walking the IR so that we can collect the
1074  // attributes/types that will actually be used during printing when
1075  // considering aliases.
1076  DummyAliasOperationPrinter aliasPrinter(printerFlags, *this);
1077  aliasPrinter.printCustomOrGenericOp(op);
1078 
1079  // Initialize the aliases.
1080  initializeAliases(aliases, attrTypeToAlias);
1081 }
1082 
1083 template <typename T, typename... PrintArgs>
1084 std::pair<size_t, size_t> AliasInitializer::visitImpl(
1085  T value, llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
1086  bool canBeDeferred, PrintArgs &&...printArgs) {
1087  auto [it, inserted] =
1088  aliases.insert({value.getAsOpaquePointer(), InProgressAliasInfo()});
1089  size_t aliasIndex = std::distance(aliases.begin(), it);
1090  if (!inserted) {
1091  // Make sure that the alias isn't deferred if we don't permit it.
1092  if (!canBeDeferred)
1093  markAliasNonDeferrable(aliasIndex);
1094  return {static_cast<size_t>(it->second.aliasDepth), aliasIndex};
1095  }
1096 
1097  // Try to generate an alias for this value.
1098  generateAlias(value, it->second, canBeDeferred);
1099 
1100  // Print the value, capturing any nested elements that require aliases.
1101  SmallVector<size_t> childAliases;
1102  DummyAliasDialectAsmPrinter printer(*this, canBeDeferred, childAliases);
1103  size_t maxAliasDepth =
1104  printer.printAndVisitNestedAliases(value, printArgs...);
1105 
1106  // Make sure to recompute `it` in case the map was reallocated.
1107  it = std::next(aliases.begin(), aliasIndex);
1108 
1109  // If we had sub elements, update to account for the depth.
1110  it->second.childIndices = std::move(childAliases);
1111  if (maxAliasDepth)
1112  it->second.aliasDepth = maxAliasDepth + 1;
1113 
1114  // Propagate the alias depth of the value.
1115  return {(size_t)it->second.aliasDepth, aliasIndex};
1116 }
1117 
1118 void AliasInitializer::markAliasNonDeferrable(size_t aliasIndex) {
1119  auto *it = std::next(aliases.begin(), aliasIndex);
1120 
1121  // If already marked non-deferrable stop the recursion.
1122  // All children should already be marked non-deferrable as well.
1123  if (!it->second.canBeDeferred)
1124  return;
1125 
1126  it->second.canBeDeferred = false;
1127 
1128  // Propagate the non-deferrable flag to any child aliases.
1129  for (size_t childIndex : it->second.childIndices)
1130  markAliasNonDeferrable(childIndex);
1131 }
1132 
1133 template <typename T>
1134 void AliasInitializer::generateAlias(T symbol, InProgressAliasInfo &alias,
1135  bool canBeDeferred) {
1136  SmallString<32> nameBuffer;
1137  for (const auto &interface : interfaces) {
1139  interface.getAlias(symbol, aliasOS);
1141  continue;
1142  nameBuffer = std::move(aliasBuffer);
1143  assert(!nameBuffer.empty() && "expected valid alias name");
1145  break;
1146  }
1147 
1148  if (nameBuffer.empty())
1149  return;
1150 
1151  SmallString<16> tempBuffer;
1152  StringRef name =
1153  sanitizeIdentifier(nameBuffer, tempBuffer, /*allowedPunctChars=*/"$_-",
1154  /*allowTrailingDigit=*/false);
1155  name = name.copy(aliasAllocator);
1156  alias = InProgressAliasInfo(name, /*isType=*/std::is_base_of_v<Type, T>,
1157  canBeDeferred);
1158 }
1159 
1160 //===----------------------------------------------------------------------===//
1161 // AliasState
1162 //===----------------------------------------------------------------------===//
1163 
1164 namespace {
1165 /// This class manages the state for type and attribute aliases.
1166 class AliasState {
1167 public:
1168  // Initialize the internal aliases.
1169  void
1170  initialize(Operation *op, const OpPrintingFlags &printerFlags,
1172 
1173  /// Get an alias for the given attribute if it has one and print it in `os`.
1174  /// Returns success if an alias was printed, failure otherwise.
1175  LogicalResult getAlias(Attribute attr, raw_ostream &os) const;
1176 
1177  /// Get an alias for the given type if it has one and print it in `os`.
1178  /// Returns success if an alias was printed, failure otherwise.
1179  LogicalResult getAlias(Type ty, raw_ostream &os) const;
1180 
1181  /// Print all of the referenced aliases that can not be resolved in a deferred
1182  /// manner.
1183  void printNonDeferredAliases(AsmPrinter::Impl &p, NewLineCounter &newLine) {
1184  printAliases(p, newLine, /*isDeferred=*/false);
1185  }
1186 
1187  /// Print all of the referenced aliases that support deferred resolution.
1188  void printDeferredAliases(AsmPrinter::Impl &p, NewLineCounter &newLine) {
1189  printAliases(p, newLine, /*isDeferred=*/true);
1190  }
1191 
1192 private:
1193  /// Print all of the referenced aliases that support the provided resolution
1194  /// behavior.
1195  void printAliases(AsmPrinter::Impl &p, NewLineCounter &newLine,
1196  bool isDeferred);
1197 
1198  /// Mapping between attribute/type and alias.
1199  llvm::MapVector<const void *, SymbolAlias> attrTypeToAlias;
1200 
1201  /// An allocator used for alias names.
1202  llvm::BumpPtrAllocator aliasAllocator;
1203 };
1204 } // namespace
1205 
1206 void AliasState::initialize(
1207  Operation *op, const OpPrintingFlags &printerFlags,
1209  AliasInitializer initializer(interfaces, aliasAllocator);
1210  initializer.initialize(op, printerFlags, attrTypeToAlias);
1211 }
1212 
1213 LogicalResult AliasState::getAlias(Attribute attr, raw_ostream &os) const {
1214  const auto *it = attrTypeToAlias.find(attr.getAsOpaquePointer());
1215  if (it == attrTypeToAlias.end())
1216  return failure();
1217  it->second.print(os);
1218  return success();
1219 }
1220 
1221 LogicalResult AliasState::getAlias(Type ty, raw_ostream &os) const {
1222  const auto *it = attrTypeToAlias.find(ty.getAsOpaquePointer());
1223  if (it == attrTypeToAlias.end())
1224  return failure();
1225 
1226  it->second.print(os);
1227  return success();
1228 }
1229 
1230 void AliasState::printAliases(AsmPrinter::Impl &p, NewLineCounter &newLine,
1231  bool isDeferred) {
1232  auto filterFn = [=](const auto &aliasIt) {
1233  return aliasIt.second.canBeDeferred() == isDeferred;
1234  };
1235  for (auto &[opaqueSymbol, alias] :
1236  llvm::make_filter_range(attrTypeToAlias, filterFn)) {
1237  alias.print(p.getStream());
1238  p.getStream() << " = ";
1239 
1240  if (alias.isTypeAlias()) {
1241  // TODO: Support nested aliases in mutable types.
1242  Type type = Type::getFromOpaquePointer(opaqueSymbol);
1243  if (type.hasTrait<TypeTrait::IsMutable>())
1244  p.getStream() << type;
1245  else
1246  p.printTypeImpl(type);
1247  } else {
1248  // TODO: Support nested aliases in mutable attributes.
1249  Attribute attr = Attribute::getFromOpaquePointer(opaqueSymbol);
1250  if (attr.hasTrait<AttributeTrait::IsMutable>())
1251  p.getStream() << attr;
1252  else
1253  p.printAttributeImpl(attr);
1254  }
1255 
1256  p.getStream() << newLine;
1257  }
1258 }
1259 
1260 //===----------------------------------------------------------------------===//
1261 // SSANameState
1262 //===----------------------------------------------------------------------===//
1263 
1264 namespace {
1265 /// Info about block printing: a number which is its position in the visitation
1266 /// order, and a name that is used to print reference to it, e.g. ^bb42.
1267 struct BlockInfo {
1268  int ordering;
1269  StringRef name;
1270 };
1271 
1272 /// This class manages the state of SSA value names.
1273 class SSANameState {
1274 public:
1275  /// A sentinel value used for values with names set.
1276  enum : unsigned { NameSentinel = ~0U };
1277 
1278  SSANameState(Operation *op, const OpPrintingFlags &printerFlags);
1279  SSANameState() = default;
1280 
1281  /// Print the SSA identifier for the given value to 'stream'. If
1282  /// 'printResultNo' is true, it also presents the result number ('#' number)
1283  /// of this value.
1284  void printValueID(Value value, bool printResultNo, raw_ostream &stream) const;
1285 
1286  /// Print the operation identifier.
1287  void printOperationID(Operation *op, raw_ostream &stream) const;
1288 
1289  /// Return the result indices for each of the result groups registered by this
1290  /// operation, or empty if none exist.
1291  ArrayRef<int> getOpResultGroups(Operation *op);
1292 
1293  /// Get the info for the given block.
1294  BlockInfo getBlockInfo(Block *block);
1295 
1296  /// Renumber the arguments for the specified region to the same names as the
1297  /// SSA values in namesToUse. See OperationPrinter::shadowRegionArgs for
1298  /// details.
1299  void shadowRegionArgs(Region &region, ValueRange namesToUse);
1300 
1301 private:
1302  /// Number the SSA values within the given IR unit.
1303  void numberValuesInRegion(Region &region);
1304  void numberValuesInBlock(Block &block);
1305  void numberValuesInOp(Operation &op);
1306 
1307  /// Given a result of an operation 'result', find the result group head
1308  /// 'lookupValue' and the result of 'result' within that group in
1309  /// 'lookupResultNo'. 'lookupResultNo' is only filled in if the result group
1310  /// has more than 1 result.
1311  void getResultIDAndNumber(OpResult result, Value &lookupValue,
1312  std::optional<int> &lookupResultNo) const;
1313 
1314  /// Set a special value name for the given value.
1315  void setValueName(Value value, StringRef name);
1316 
1317  /// Uniques the given value name within the printer. If the given name
1318  /// conflicts, it is automatically renamed.
1319  StringRef uniqueValueName(StringRef name);
1320 
1321  /// This is the value ID for each SSA value. If this returns NameSentinel,
1322  /// then the valueID has an entry in valueNames.
1323  DenseMap<Value, unsigned> valueIDs;
1324  DenseMap<Value, StringRef> valueNames;
1325 
1326  /// When printing users of values, an operation without a result might
1327  /// be the user. This map holds ids for such operations.
1328  DenseMap<Operation *, unsigned> operationIDs;
1329 
1330  /// This is a map of operations that contain multiple named result groups,
1331  /// i.e. there may be multiple names for the results of the operation. The
1332  /// value of this map are the result numbers that start a result group.
1334 
1335  /// This maps blocks to there visitation number in the current region as well
1336  /// as the string representing their name.
1337  DenseMap<Block *, BlockInfo> blockNames;
1338 
1339  /// This keeps track of all of the non-numeric names that are in flight,
1340  /// allowing us to check for duplicates.
1341  /// Note: the value of the map is unused.
1342  llvm::ScopedHashTable<StringRef, char> usedNames;
1343  llvm::BumpPtrAllocator usedNameAllocator;
1344 
1345  /// This is the next value ID to assign in numbering.
1346  unsigned nextValueID = 0;
1347  /// This is the next ID to assign to a region entry block argument.
1348  unsigned nextArgumentID = 0;
1349  /// This is the next ID to assign when a name conflict is detected.
1350  unsigned nextConflictID = 0;
1351 
1352  /// These are the printing flags. They control, eg., whether to print in
1353  /// generic form.
1354  OpPrintingFlags printerFlags;
1355 };
1356 } // namespace
1357 
1358 SSANameState::SSANameState(Operation *op, const OpPrintingFlags &printerFlags)
1359  : printerFlags(printerFlags) {
1360  llvm::SaveAndRestore valueIDSaver(nextValueID);
1361  llvm::SaveAndRestore argumentIDSaver(nextArgumentID);
1362  llvm::SaveAndRestore conflictIDSaver(nextConflictID);
1363 
1364  // The naming context includes `nextValueID`, `nextArgumentID`,
1365  // `nextConflictID` and `usedNames` scoped HashTable. This information is
1366  // carried from the parent region.
1367  using UsedNamesScopeTy = llvm::ScopedHashTable<StringRef, char>::ScopeTy;
1368  using NamingContext =
1369  std::tuple<Region *, unsigned, unsigned, unsigned, UsedNamesScopeTy *>;
1370 
1371  // Allocator for UsedNamesScopeTy
1372  llvm::BumpPtrAllocator allocator;
1373 
1374  // Add a scope for the top level operation.
1375  auto *topLevelNamesScope =
1376  new (allocator.Allocate<UsedNamesScopeTy>()) UsedNamesScopeTy(usedNames);
1377 
1378  SmallVector<NamingContext, 8> nameContext;
1379  for (Region &region : op->getRegions())
1380  nameContext.push_back(std::make_tuple(&region, nextValueID, nextArgumentID,
1381  nextConflictID, topLevelNamesScope));
1382 
1383  numberValuesInOp(*op);
1384 
1385  while (!nameContext.empty()) {
1386  Region *region;
1387  UsedNamesScopeTy *parentScope;
1388 
1389  if (printerFlags.shouldPrintUniqueSSAIDs())
1390  // To print unique SSA IDs, ignore saved ID counts from parent regions
1391  std::tie(region, std::ignore, std::ignore, std::ignore, parentScope) =
1392  nameContext.pop_back_val();
1393  else
1394  std::tie(region, nextValueID, nextArgumentID, nextConflictID,
1395  parentScope) = nameContext.pop_back_val();
1396 
1397  // When we switch from one subtree to another, pop the scopes(needless)
1398  // until the parent scope.
1399  while (usedNames.getCurScope() != parentScope) {
1400  usedNames.getCurScope()->~UsedNamesScopeTy();
1401  assert((usedNames.getCurScope() != nullptr || parentScope == nullptr) &&
1402  "top level parentScope must be a nullptr");
1403  }
1404 
1405  // Add a scope for the current region.
1406  auto *curNamesScope = new (allocator.Allocate<UsedNamesScopeTy>())
1407  UsedNamesScopeTy(usedNames);
1408 
1409  numberValuesInRegion(*region);
1410 
1411  for (Operation &op : region->getOps())
1412  for (Region &region : op.getRegions())
1413  nameContext.push_back(std::make_tuple(&region, nextValueID,
1414  nextArgumentID, nextConflictID,
1415  curNamesScope));
1416  }
1417 
1418  // Manually remove all the scopes.
1419  while (usedNames.getCurScope() != nullptr)
1420  usedNames.getCurScope()->~UsedNamesScopeTy();
1421 }
1422 
1423 void SSANameState::printValueID(Value value, bool printResultNo,
1424  raw_ostream &stream) const {
1425  if (!value) {
1426  stream << "<<NULL VALUE>>";
1427  return;
1428  }
1429 
1430  std::optional<int> resultNo;
1431  auto lookupValue = value;
1432 
1433  // If this is an operation result, collect the head lookup value of the result
1434  // group and the result number of 'result' within that group.
1435  if (OpResult result = dyn_cast<OpResult>(value))
1436  getResultIDAndNumber(result, lookupValue, resultNo);
1437 
1438  auto it = valueIDs.find(lookupValue);
1439  if (it == valueIDs.end()) {
1440  stream << "<<UNKNOWN SSA VALUE>>";
1441  return;
1442  }
1443 
1444  stream << '%';
1445  if (it->second != NameSentinel) {
1446  stream << it->second;
1447  } else {
1448  auto nameIt = valueNames.find(lookupValue);
1449  assert(nameIt != valueNames.end() && "Didn't have a name entry?");
1450  stream << nameIt->second;
1451  }
1452 
1453  if (resultNo && printResultNo)
1454  stream << '#' << *resultNo;
1455 }
1456 
1457 void SSANameState::printOperationID(Operation *op, raw_ostream &stream) const {
1458  auto it = operationIDs.find(op);
1459  if (it == operationIDs.end()) {
1460  stream << "<<UNKNOWN OPERATION>>";
1461  } else {
1462  stream << '%' << it->second;
1463  }
1464 }
1465 
1466 ArrayRef<int> SSANameState::getOpResultGroups(Operation *op) {
1467  auto it = opResultGroups.find(op);
1468  return it == opResultGroups.end() ? ArrayRef<int>() : it->second;
1469 }
1470 
1471 BlockInfo SSANameState::getBlockInfo(Block *block) {
1472  auto it = blockNames.find(block);
1473  BlockInfo invalidBlock{-1, "INVALIDBLOCK"};
1474  return it != blockNames.end() ? it->second : invalidBlock;
1475 }
1476 
1477 void SSANameState::shadowRegionArgs(Region &region, ValueRange namesToUse) {
1478  assert(!region.empty() && "cannot shadow arguments of an empty region");
1479  assert(region.getNumArguments() == namesToUse.size() &&
1480  "incorrect number of names passed in");
1481  assert(region.getParentOp()->hasTrait<OpTrait::IsIsolatedFromAbove>() &&
1482  "only KnownIsolatedFromAbove ops can shadow names");
1483 
1484  SmallVector<char, 16> nameStr;
1485  for (unsigned i = 0, e = namesToUse.size(); i != e; ++i) {
1486  auto nameToUse = namesToUse[i];
1487  if (nameToUse == nullptr)
1488  continue;
1489  auto nameToReplace = region.getArgument(i);
1490 
1491  nameStr.clear();
1492  llvm::raw_svector_ostream nameStream(nameStr);
1493  printValueID(nameToUse, /*printResultNo=*/true, nameStream);
1494 
1495  // Entry block arguments should already have a pretty "arg" name.
1496  assert(valueIDs[nameToReplace] == NameSentinel);
1497 
1498  // Use the name without the leading %.
1499  auto name = StringRef(nameStream.str()).drop_front();
1500 
1501  // Overwrite the name.
1502  valueNames[nameToReplace] = name.copy(usedNameAllocator);
1503  }
1504 }
1505 
1506 void SSANameState::numberValuesInRegion(Region &region) {
1507  auto setBlockArgNameFn = [&](Value arg, StringRef name) {
1508  assert(!valueIDs.count(arg) && "arg numbered multiple times");
1509  assert(llvm::cast<BlockArgument>(arg).getOwner()->getParent() == &region &&
1510  "arg not defined in current region");
1511  setValueName(arg, name);
1512  };
1513 
1514  if (!printerFlags.shouldPrintGenericOpForm()) {
1515  if (Operation *op = region.getParentOp()) {
1516  if (auto asmInterface = dyn_cast<OpAsmOpInterface>(op))
1517  asmInterface.getAsmBlockArgumentNames(region, setBlockArgNameFn);
1518  }
1519  }
1520 
1521  // Number the values within this region in a breadth-first order.
1522  unsigned nextBlockID = 0;
1523  for (auto &block : region) {
1524  // Each block gets a unique ID, and all of the operations within it get
1525  // numbered as well.
1526  auto blockInfoIt = blockNames.insert({&block, {-1, ""}});
1527  if (blockInfoIt.second) {
1528  // This block hasn't been named through `getAsmBlockArgumentNames`, use
1529  // default `^bbNNN` format.
1530  std::string name;
1531  llvm::raw_string_ostream(name) << "^bb" << nextBlockID;
1532  blockInfoIt.first->second.name = StringRef(name).copy(usedNameAllocator);
1533  }
1534  blockInfoIt.first->second.ordering = nextBlockID++;
1535 
1536  numberValuesInBlock(block);
1537  }
1538 }
1539 
1540 void SSANameState::numberValuesInBlock(Block &block) {
1541  // Number the block arguments. We give entry block arguments a special name
1542  // 'arg'.
1543  bool isEntryBlock = block.isEntryBlock();
1544  SmallString<32> specialNameBuffer(isEntryBlock ? "arg" : "");
1545  llvm::raw_svector_ostream specialName(specialNameBuffer);
1546  for (auto arg : block.getArguments()) {
1547  if (valueIDs.count(arg))
1548  continue;
1549  if (isEntryBlock) {
1550  specialNameBuffer.resize(strlen("arg"));
1551  specialName << nextArgumentID++;
1552  }
1553  setValueName(arg, specialName.str());
1554  }
1555 
1556  // Number the operations in this block.
1557  for (auto &op : block)
1558  numberValuesInOp(op);
1559 }
1560 
1561 void SSANameState::numberValuesInOp(Operation &op) {
1562  // Function used to set the special result names for the operation.
1563  SmallVector<int, 2> resultGroups(/*Size=*/1, /*Value=*/0);
1564  auto setResultNameFn = [&](Value result, StringRef name) {
1565  assert(!valueIDs.count(result) && "result numbered multiple times");
1566  assert(result.getDefiningOp() == &op && "result not defined by 'op'");
1567  setValueName(result, name);
1568 
1569  // Record the result number for groups not anchored at 0.
1570  if (int resultNo = llvm::cast<OpResult>(result).getResultNumber())
1571  resultGroups.push_back(resultNo);
1572  };
1573  // Operations can customize the printing of block names in OpAsmOpInterface.
1574  auto setBlockNameFn = [&](Block *block, StringRef name) {
1575  assert(block->getParentOp() == &op &&
1576  "getAsmBlockArgumentNames callback invoked on a block not directly "
1577  "nested under the current operation");
1578  assert(!blockNames.count(block) && "block numbered multiple times");
1579  SmallString<16> tmpBuffer{"^"};
1580  name = sanitizeIdentifier(name, tmpBuffer);
1581  if (name.data() != tmpBuffer.data()) {
1582  tmpBuffer.append(name);
1583  name = tmpBuffer.str();
1584  }
1585  name = name.copy(usedNameAllocator);
1586  blockNames[block] = {-1, name};
1587  };
1588 
1589  if (!printerFlags.shouldPrintGenericOpForm()) {
1590  if (OpAsmOpInterface asmInterface = dyn_cast<OpAsmOpInterface>(&op)) {
1591  asmInterface.getAsmBlockNames(setBlockNameFn);
1592  asmInterface.getAsmResultNames(setResultNameFn);
1593  }
1594  }
1595 
1596  unsigned numResults = op.getNumResults();
1597  if (numResults == 0) {
1598  // If value users should be printed, operations with no result need an id.
1599  if (printerFlags.shouldPrintValueUsers()) {
1600  if (operationIDs.try_emplace(&op, nextValueID).second)
1601  ++nextValueID;
1602  }
1603  return;
1604  }
1605  Value resultBegin = op.getResult(0);
1606 
1607  // If the first result wasn't numbered, give it a default number.
1608  if (valueIDs.try_emplace(resultBegin, nextValueID).second)
1609  ++nextValueID;
1610 
1611  // If this operation has multiple result groups, mark it.
1612  if (resultGroups.size() != 1) {
1613  llvm::array_pod_sort(resultGroups.begin(), resultGroups.end());
1614  opResultGroups.try_emplace(&op, std::move(resultGroups));
1615  }
1616 }
1617 
1618 void SSANameState::getResultIDAndNumber(
1619  OpResult result, Value &lookupValue,
1620  std::optional<int> &lookupResultNo) const {
1621  Operation *owner = result.getOwner();
1622  if (owner->getNumResults() == 1)
1623  return;
1624  int resultNo = result.getResultNumber();
1625 
1626  // If this operation has multiple result groups, we will need to find the
1627  // one corresponding to this result.
1628  auto resultGroupIt = opResultGroups.find(owner);
1629  if (resultGroupIt == opResultGroups.end()) {
1630  // If not, just use the first result.
1631  lookupResultNo = resultNo;
1632  lookupValue = owner->getResult(0);
1633  return;
1634  }
1635 
1636  // Find the correct index using a binary search, as the groups are ordered.
1637  ArrayRef<int> resultGroups = resultGroupIt->second;
1638  const auto *it = llvm::upper_bound(resultGroups, resultNo);
1639  int groupResultNo = 0, groupSize = 0;
1640 
1641  // If there are no smaller elements, the last result group is the lookup.
1642  if (it == resultGroups.end()) {
1643  groupResultNo = resultGroups.back();
1644  groupSize = static_cast<int>(owner->getNumResults()) - resultGroups.back();
1645  } else {
1646  // Otherwise, the previous element is the lookup.
1647  groupResultNo = *std::prev(it);
1648  groupSize = *it - groupResultNo;
1649  }
1650 
1651  // We only record the result number for a group of size greater than 1.
1652  if (groupSize != 1)
1653  lookupResultNo = resultNo - groupResultNo;
1654  lookupValue = owner->getResult(groupResultNo);
1655 }
1656 
1657 void SSANameState::setValueName(Value value, StringRef name) {
1658  // If the name is empty, the value uses the default numbering.
1659  if (name.empty()) {
1660  valueIDs[value] = nextValueID++;
1661  return;
1662  }
1663 
1664  valueIDs[value] = NameSentinel;
1665  valueNames[value] = uniqueValueName(name);
1666 }
1667 
1668 StringRef SSANameState::uniqueValueName(StringRef name) {
1669  SmallString<16> tmpBuffer;
1670  name = sanitizeIdentifier(name, tmpBuffer);
1671 
1672  // Check to see if this name is already unique.
1673  if (!usedNames.count(name)) {
1674  name = name.copy(usedNameAllocator);
1675  } else {
1676  // Otherwise, we had a conflict - probe until we find a unique name. This
1677  // is guaranteed to terminate (and usually in a single iteration) because it
1678  // generates new names by incrementing nextConflictID.
1679  SmallString<64> probeName(name);
1680  probeName.push_back('_');
1681  while (true) {
1682  probeName += llvm::utostr(nextConflictID++);
1683  if (!usedNames.count(probeName)) {
1684  name = probeName.str().copy(usedNameAllocator);
1685  break;
1686  }
1687  probeName.resize(name.size() + 1);
1688  }
1689  }
1690 
1691  usedNames.insert(name, char());
1692  return name;
1693 }
1694 
1695 //===----------------------------------------------------------------------===//
1696 // DistinctState
1697 //===----------------------------------------------------------------------===//
1698 
1699 namespace {
1700 /// This class manages the state for distinct attributes.
1701 class DistinctState {
1702 public:
1703  /// Returns a unique identifier for the given distinct attribute.
1704  uint64_t getId(DistinctAttr distinctAttr);
1705 
1706 private:
1707  uint64_t distinctCounter = 0;
1708  DenseMap<DistinctAttr, uint64_t> distinctAttrMap;
1709 };
1710 } // namespace
1711 
1712 uint64_t DistinctState::getId(DistinctAttr distinctAttr) {
1713  auto [it, inserted] =
1714  distinctAttrMap.try_emplace(distinctAttr, distinctCounter);
1715  if (inserted)
1716  distinctCounter++;
1717  return it->getSecond();
1718 }
1719 
1720 //===----------------------------------------------------------------------===//
1721 // Resources
1722 //===----------------------------------------------------------------------===//
1723 
1724 AsmParsedResourceEntry::~AsmParsedResourceEntry() = default;
1725 AsmResourceBuilder::~AsmResourceBuilder() = default;
1726 AsmResourceParser::~AsmResourceParser() = default;
1727 AsmResourcePrinter::~AsmResourcePrinter() = default;
1728 
1730  switch (kind) {
1731  case AsmResourceEntryKind::Blob:
1732  return "blob";
1733  case AsmResourceEntryKind::Bool:
1734  return "bool";
1735  case AsmResourceEntryKind::String:
1736  return "string";
1737  }
1738  llvm_unreachable("unknown AsmResourceEntryKind");
1739 }
1740 
1741 AsmResourceParser &FallbackAsmResourceMap::getParserFor(StringRef key) {
1742  std::unique_ptr<ResourceCollection> &collection = keyToResources[key.str()];
1743  if (!collection)
1744  collection = std::make_unique<ResourceCollection>(key);
1745  return *collection;
1746 }
1747 
1748 std::vector<std::unique_ptr<AsmResourcePrinter>>
1750  std::vector<std::unique_ptr<AsmResourcePrinter>> printers;
1751  for (auto &it : keyToResources) {
1752  ResourceCollection *collection = it.second.get();
1753  auto buildValues = [=](Operation *op, AsmResourceBuilder &builder) {
1754  return collection->buildResources(op, builder);
1755  };
1756  printers.emplace_back(
1757  AsmResourcePrinter::fromCallable(collection->getName(), buildValues));
1758  }
1759  return printers;
1760 }
1761 
1762 LogicalResult FallbackAsmResourceMap::ResourceCollection::parseResource(
1763  AsmParsedResourceEntry &entry) {
1764  switch (entry.getKind()) {
1766  FailureOr<AsmResourceBlob> blob = entry.parseAsBlob();
1767  if (failed(blob))
1768  return failure();
1769  resources.emplace_back(entry.getKey(), std::move(*blob));
1770  return success();
1771  }
1773  FailureOr<bool> value = entry.parseAsBool();
1774  if (failed(value))
1775  return failure();
1776  resources.emplace_back(entry.getKey(), *value);
1777  break;
1778  }
1780  FailureOr<std::string> str = entry.parseAsString();
1781  if (failed(str))
1782  return failure();
1783  resources.emplace_back(entry.getKey(), std::move(*str));
1784  break;
1785  }
1786  }
1787  return success();
1788 }
1789 
1790 void FallbackAsmResourceMap::ResourceCollection::buildResources(
1791  Operation *op, AsmResourceBuilder &builder) const {
1792  for (const auto &entry : resources) {
1793  if (const auto *value = std::get_if<AsmResourceBlob>(&entry.value))
1794  builder.buildBlob(entry.key, *value);
1795  else if (const auto *value = std::get_if<bool>(&entry.value))
1796  builder.buildBool(entry.key, *value);
1797  else if (const auto *value = std::get_if<std::string>(&entry.value))
1798  builder.buildString(entry.key, *value);
1799  else
1800  llvm_unreachable("unknown AsmResourceEntryKind");
1801  }
1802 }
1803 
1804 //===----------------------------------------------------------------------===//
1805 // AsmState
1806 //===----------------------------------------------------------------------===//
1807 
1808 namespace mlir {
1809 namespace detail {
1811 public:
1812  explicit AsmStateImpl(Operation *op, const OpPrintingFlags &printerFlags,
1813  AsmState::LocationMap *locationMap)
1814  : interfaces(op->getContext()), nameState(op, printerFlags),
1815  printerFlags(printerFlags), locationMap(locationMap) {}
1816  explicit AsmStateImpl(MLIRContext *ctx, const OpPrintingFlags &printerFlags,
1817  AsmState::LocationMap *locationMap)
1818  : interfaces(ctx), printerFlags(printerFlags), locationMap(locationMap) {}
1819 
1820  /// Initialize the alias state to enable the printing of aliases.
1822  aliasState.initialize(op, printerFlags, interfaces);
1823  }
1824 
1825  /// Get the state used for aliases.
1826  AliasState &getAliasState() { return aliasState; }
1827 
1828  /// Get the state used for SSA names.
1829  SSANameState &getSSANameState() { return nameState; }
1830 
1831  /// Get the state used for distinct attribute identifiers.
1832  DistinctState &getDistinctState() { return distinctState; }
1833 
1834  /// Return the dialects within the context that implement
1835  /// OpAsmDialectInterface.
1837  return interfaces;
1838  }
1839 
1840  /// Return the non-dialect resource printers.
1842  return llvm::make_pointee_range(externalResourcePrinters);
1843  }
1844 
1845  /// Get the printer flags.
1846  const OpPrintingFlags &getPrinterFlags() const { return printerFlags; }
1847 
1848  /// Register the location, line and column, within the buffer that the given
1849  /// operation was printed at.
1850  void registerOperationLocation(Operation *op, unsigned line, unsigned col) {
1851  if (locationMap)
1852  (*locationMap)[op] = std::make_pair(line, col);
1853  }
1854 
1855  /// Return the referenced dialect resources within the printer.
1858  return dialectResources;
1859  }
1860 
1861  LogicalResult pushCyclicPrinting(const void *opaquePointer) {
1862  return success(cyclicPrintingStack.insert(opaquePointer));
1863  }
1864 
1865  void popCyclicPrinting() { cyclicPrintingStack.pop_back(); }
1866 
1867 private:
1868  /// Collection of OpAsm interfaces implemented in the context.
1870 
1871  /// A collection of non-dialect resource printers.
1872  SmallVector<std::unique_ptr<AsmResourcePrinter>> externalResourcePrinters;
1873 
1874  /// A set of dialect resources that were referenced during printing.
1876 
1877  /// The state used for attribute and type aliases.
1878  AliasState aliasState;
1879 
1880  /// The state used for SSA value names.
1881  SSANameState nameState;
1882 
1883  /// The state used for distinct attribute identifiers.
1884  DistinctState distinctState;
1885 
1886  /// Flags that control op output.
1887  OpPrintingFlags printerFlags;
1888 
1889  /// An optional location map to be populated.
1890  AsmState::LocationMap *locationMap;
1891 
1892  /// Stack of potentially cyclic mutable attributes or type currently being
1893  /// printed.
1894  SetVector<const void *> cyclicPrintingStack;
1895 
1896  // Allow direct access to the impl fields.
1897  friend AsmState;
1898 };
1899 
1900 template <typename Range>
1901 void printDimensionList(raw_ostream &stream, Range &&shape) {
1902  llvm::interleave(
1903  shape, stream,
1904  [&stream](const auto &dimSize) {
1905  if (ShapedType::isDynamic(dimSize))
1906  stream << "?";
1907  else
1908  stream << dimSize;
1909  },
1910  "x");
1911 }
1912 
1913 } // namespace detail
1914 } // namespace mlir
1915 
1916 /// Verifies the operation and switches to generic op printing if verification
1917 /// fails. We need to do this because custom print functions may fail for
1918 /// invalid ops.
1920  OpPrintingFlags printerFlags) {
1921  if (printerFlags.shouldPrintGenericOpForm() ||
1922  printerFlags.shouldAssumeVerified())
1923  return printerFlags;
1924 
1925  // Ignore errors emitted by the verifier. We check the thread id to avoid
1926  // consuming other threads' errors.
1927  auto parentThreadId = llvm::get_threadid();
1928  ScopedDiagnosticHandler diagHandler(op->getContext(), [&](Diagnostic &diag) {
1929  if (parentThreadId == llvm::get_threadid()) {
1930  LLVM_DEBUG({
1931  diag.print(llvm::dbgs());
1932  llvm::dbgs() << "\n";
1933  });
1934  return success();
1935  }
1936  return failure();
1937  });
1938  if (failed(verify(op))) {
1939  LLVM_DEBUG(llvm::dbgs()
1940  << DEBUG_TYPE << ": '" << op->getName()
1941  << "' failed to verify and will be printed in generic form\n");
1942  printerFlags.printGenericOpForm();
1943  }
1944 
1945  return printerFlags;
1946 }
1947 
1948 AsmState::AsmState(Operation *op, const OpPrintingFlags &printerFlags,
1949  LocationMap *locationMap, FallbackAsmResourceMap *map)
1950  : impl(std::make_unique<AsmStateImpl>(
1951  op, verifyOpAndAdjustFlags(op, printerFlags), locationMap)) {
1952  if (map)
1954 }
1955 AsmState::AsmState(MLIRContext *ctx, const OpPrintingFlags &printerFlags,
1956  LocationMap *locationMap, FallbackAsmResourceMap *map)
1957  : impl(std::make_unique<AsmStateImpl>(ctx, printerFlags, locationMap)) {
1958  if (map)
1960 }
1961 AsmState::~AsmState() = default;
1962 
1964  return impl->getPrinterFlags();
1965 }
1966 
1968  std::unique_ptr<AsmResourcePrinter> printer) {
1969  impl->externalResourcePrinters.emplace_back(std::move(printer));
1970 }
1971 
1974  return impl->getDialectResources();
1975 }
1976 
1977 //===----------------------------------------------------------------------===//
1978 // AsmPrinter::Impl
1979 //===----------------------------------------------------------------------===//
1980 
1981 AsmPrinter::Impl::Impl(raw_ostream &os, AsmStateImpl &state)
1982  : os(os), state(state), printerFlags(state.getPrinterFlags()) {}
1983 
1985  // Check to see if we are printing debug information.
1986  if (!printerFlags.shouldPrintDebugInfo())
1987  return;
1988 
1989  os << " ";
1990  printLocation(loc, /*allowAlias=*/allowAlias);
1991 }
1992 
1994  bool isTopLevel) {
1995  // If this isn't a top-level location, check for an alias.
1996  if (!isTopLevel && succeeded(state.getAliasState().getAlias(loc, os)))
1997  return;
1998 
2000  .Case<OpaqueLoc>([&](OpaqueLoc loc) {
2001  printLocationInternal(loc.getFallbackLocation(), pretty);
2002  })
2003  .Case<UnknownLoc>([&](UnknownLoc loc) {
2004  if (pretty)
2005  os << "[unknown]";
2006  else
2007  os << "unknown";
2008  })
2009  .Case<FileLineColLoc>([&](FileLineColLoc loc) {
2010  if (pretty)
2011  os << loc.getFilename().getValue();
2012  else
2013  printEscapedString(loc.getFilename());
2014  os << ':' << loc.getLine() << ':' << loc.getColumn();
2015  })
2016  .Case<NameLoc>([&](NameLoc loc) {
2017  printEscapedString(loc.getName());
2018 
2019  // Print the child if it isn't unknown.
2020  auto childLoc = loc.getChildLoc();
2021  if (!llvm::isa<UnknownLoc>(childLoc)) {
2022  os << '(';
2023  printLocationInternal(childLoc, pretty);
2024  os << ')';
2025  }
2026  })
2027  .Case<CallSiteLoc>([&](CallSiteLoc loc) {
2028  Location caller = loc.getCaller();
2029  Location callee = loc.getCallee();
2030  if (!pretty)
2031  os << "callsite(";
2032  printLocationInternal(callee, pretty);
2033  if (pretty) {
2034  if (llvm::isa<NameLoc>(callee)) {
2035  if (llvm::isa<FileLineColLoc>(caller)) {
2036  os << " at ";
2037  } else {
2038  os << newLine << " at ";
2039  }
2040  } else {
2041  os << newLine << " at ";
2042  }
2043  } else {
2044  os << " at ";
2045  }
2046  printLocationInternal(caller, pretty);
2047  if (!pretty)
2048  os << ")";
2049  })
2050  .Case<FusedLoc>([&](FusedLoc loc) {
2051  if (!pretty)
2052  os << "fused";
2053  if (Attribute metadata = loc.getMetadata()) {
2054  os << '<';
2055  printAttribute(metadata);
2056  os << '>';
2057  }
2058  os << '[';
2059  interleave(
2060  loc.getLocations(),
2061  [&](Location loc) { printLocationInternal(loc, pretty); },
2062  [&]() { os << ", "; });
2063  os << ']';
2064  });
2065 }
2066 
2067 /// Print a floating point value in a way that the parser will be able to
2068 /// round-trip losslessly.
2069 static void printFloatValue(const APFloat &apValue, raw_ostream &os,
2070  bool *printedHex = nullptr) {
2071  // We would like to output the FP constant value in exponential notation,
2072  // but we cannot do this if doing so will lose precision. Check here to
2073  // make sure that we only output it in exponential format if we can parse
2074  // the value back and get the same value.
2075  bool isInf = apValue.isInfinity();
2076  bool isNaN = apValue.isNaN();
2077  if (!isInf && !isNaN) {
2078  SmallString<128> strValue;
2079  apValue.toString(strValue, /*FormatPrecision=*/6, /*FormatMaxPadding=*/0,
2080  /*TruncateZero=*/false);
2081 
2082  // Check to make sure that the stringized number is not some string like
2083  // "Inf" or NaN, that atof will accept, but the lexer will not. Check
2084  // that the string matches the "[-+]?[0-9]" regex.
2085  assert(((strValue[0] >= '0' && strValue[0] <= '9') ||
2086  ((strValue[0] == '-' || strValue[0] == '+') &&
2087  (strValue[1] >= '0' && strValue[1] <= '9'))) &&
2088  "[-+]?[0-9] regex does not match!");
2089 
2090  // Parse back the stringized version and check that the value is equal
2091  // (i.e., there is no precision loss).
2092  if (APFloat(apValue.getSemantics(), strValue).bitwiseIsEqual(apValue)) {
2093  os << strValue;
2094  return;
2095  }
2096 
2097  // If it is not, use the default format of APFloat instead of the
2098  // exponential notation.
2099  strValue.clear();
2100  apValue.toString(strValue);
2101 
2102  // Make sure that we can parse the default form as a float.
2103  if (strValue.str().contains('.')) {
2104  os << strValue;
2105  return;
2106  }
2107  }
2108 
2109  // Print special values in hexadecimal format. The sign bit should be included
2110  // in the literal.
2111  if (printedHex)
2112  *printedHex = true;
2114  APInt apInt = apValue.bitcastToAPInt();
2115  apInt.toString(str, /*Radix=*/16, /*Signed=*/false,
2116  /*formatAsCLiteral=*/true);
2117  os << str;
2118 }
2119 
2120 void AsmPrinter::Impl::printLocation(LocationAttr loc, bool allowAlias) {
2121  if (printerFlags.shouldPrintDebugInfoPrettyForm())
2122  return printLocationInternal(loc, /*pretty=*/true, /*isTopLevel=*/true);
2123 
2124  os << "loc(";
2125  if (!allowAlias || failed(printAlias(loc)))
2126  printLocationInternal(loc, /*pretty=*/false, /*isTopLevel=*/true);
2127  os << ')';
2128 }
2129 
2131  const AsmDialectResourceHandle &resource) {
2132  auto *interface = cast<OpAsmDialectInterface>(resource.getDialect());
2133  os << interface->getResourceKey(resource);
2134  state.getDialectResources()[resource.getDialect()].insert(resource);
2135 }
2136 
2137 /// Returns true if the given dialect symbol data is simple enough to print in
2138 /// the pretty form. This is essentially when the symbol takes the form:
2139 /// identifier (`<` body `>`)?
2140 static bool isDialectSymbolSimpleEnoughForPrettyForm(StringRef symName) {
2141  // The name must start with an identifier.
2142  if (symName.empty() || !isalpha(symName.front()))
2143  return false;
2144 
2145  // Ignore all the characters that are valid in an identifier in the symbol
2146  // name.
2147  symName = symName.drop_while(
2148  [](char c) { return llvm::isAlnum(c) || c == '.' || c == '_'; });
2149  if (symName.empty())
2150  return true;
2151 
2152  // If we got to an unexpected character, then it must be a <>. Check that the
2153  // rest of the symbol is wrapped within <>.
2154  return symName.front() == '<' && symName.back() == '>';
2155 }
2156 
2157 /// Print the given dialect symbol to the stream.
2158 static void printDialectSymbol(raw_ostream &os, StringRef symPrefix,
2159  StringRef dialectName, StringRef symString) {
2160  os << symPrefix << dialectName;
2161 
2162  // If this symbol name is simple enough, print it directly in pretty form,
2163  // otherwise, we print it as an escaped string.
2165  os << '.' << symString;
2166  return;
2167  }
2168 
2169  os << '<' << symString << '>';
2170 }
2171 
2172 /// Returns true if the given string can be represented as a bare identifier.
2173 static bool isBareIdentifier(StringRef name) {
2174  // By making this unsigned, the value passed in to isalnum will always be
2175  // in the range 0-255. This is important when building with MSVC because
2176  // its implementation will assert. This situation can arise when dealing
2177  // with UTF-8 multibyte characters.
2178  if (name.empty() || (!isalpha(name[0]) && name[0] != '_'))
2179  return false;
2180  return llvm::all_of(name.drop_front(), [](unsigned char c) {
2181  return isalnum(c) || c == '_' || c == '$' || c == '.';
2182  });
2183 }
2184 
2185 /// Print the given string as a keyword, or a quoted and escaped string if it
2186 /// has any special or non-printable characters in it.
2187 static void printKeywordOrString(StringRef keyword, raw_ostream &os) {
2188  // If it can be represented as a bare identifier, write it directly.
2189  if (isBareIdentifier(keyword)) {
2190  os << keyword;
2191  return;
2192  }
2193 
2194  // Otherwise, output the keyword wrapped in quotes with proper escaping.
2195  os << "\"";
2196  printEscapedString(keyword, os);
2197  os << '"';
2198 }
2199 
2200 /// Print the given string as a symbol reference. A symbol reference is
2201 /// represented as a string prefixed with '@'. The reference is surrounded with
2202 /// ""'s and escaped if it has any special or non-printable characters in it.
2203 static void printSymbolReference(StringRef symbolRef, raw_ostream &os) {
2204  if (symbolRef.empty()) {
2205  os << "@<<INVALID EMPTY SYMBOL>>";
2206  return;
2207  }
2208  os << '@';
2209  printKeywordOrString(symbolRef, os);
2210 }
2211 
2212 // Print out a valid ElementsAttr that is succinct and can represent any
2213 // potential shape/type, for use when eliding a large ElementsAttr.
2214 //
2215 // We choose to use a dense resource ElementsAttr literal with conspicuous
2216 // content to hopefully alert readers to the fact that this has been elided.
2217 static void printElidedElementsAttr(raw_ostream &os) {
2218  os << R"(dense_resource<__elided__>)";
2219 }
2220 
2221 LogicalResult AsmPrinter::Impl::printAlias(Attribute attr) {
2222  return state.getAliasState().getAlias(attr, os);
2223 }
2224 
2225 LogicalResult AsmPrinter::Impl::printAlias(Type type) {
2226  return state.getAliasState().getAlias(type, os);
2227 }
2228 
2229 void AsmPrinter::Impl::printAttribute(Attribute attr,
2230  AttrTypeElision typeElision) {
2231  if (!attr) {
2232  os << "<<NULL ATTRIBUTE>>";
2233  return;
2234  }
2235 
2236  // Try to print an alias for this attribute.
2237  if (succeeded(printAlias(attr)))
2238  return;
2239  return printAttributeImpl(attr, typeElision);
2240 }
2241 
2242 void AsmPrinter::Impl::printAttributeImpl(Attribute attr,
2243  AttrTypeElision typeElision) {
2244  if (!isa<BuiltinDialect>(attr.getDialect())) {
2245  printDialectAttribute(attr);
2246  } else if (auto opaqueAttr = llvm::dyn_cast<OpaqueAttr>(attr)) {
2247  printDialectSymbol(os, "#", opaqueAttr.getDialectNamespace(),
2248  opaqueAttr.getAttrData());
2249  } else if (llvm::isa<UnitAttr>(attr)) {
2250  os << "unit";
2251  return;
2252  } else if (auto distinctAttr = llvm::dyn_cast<DistinctAttr>(attr)) {
2253  os << "distinct[" << state.getDistinctState().getId(distinctAttr) << "]<";
2254  if (!llvm::isa<UnitAttr>(distinctAttr.getReferencedAttr())) {
2255  printAttribute(distinctAttr.getReferencedAttr());
2256  }
2257  os << '>';
2258  return;
2259  } else if (auto dictAttr = llvm::dyn_cast<DictionaryAttr>(attr)) {
2260  os << '{';
2261  interleaveComma(dictAttr.getValue(),
2262  [&](NamedAttribute attr) { printNamedAttribute(attr); });
2263  os << '}';
2264 
2265  } else if (auto intAttr = llvm::dyn_cast<IntegerAttr>(attr)) {
2266  Type intType = intAttr.getType();
2267  if (intType.isSignlessInteger(1)) {
2268  os << (intAttr.getValue().getBoolValue() ? "true" : "false");
2269 
2270  // Boolean integer attributes always elides the type.
2271  return;
2272  }
2273 
2274  // Only print attributes as unsigned if they are explicitly unsigned or are
2275  // signless 1-bit values. Indexes, signed values, and multi-bit signless
2276  // values print as signed.
2277  bool isUnsigned =
2278  intType.isUnsignedInteger() || intType.isSignlessInteger(1);
2279  intAttr.getValue().print(os, !isUnsigned);
2280 
2281  // IntegerAttr elides the type if I64.
2282  if (typeElision == AttrTypeElision::May && intType.isSignlessInteger(64))
2283  return;
2284 
2285  } else if (auto floatAttr = llvm::dyn_cast<FloatAttr>(attr)) {
2286  bool printedHex = false;
2287  printFloatValue(floatAttr.getValue(), os, &printedHex);
2288 
2289  // FloatAttr elides the type if F64.
2290  if (typeElision == AttrTypeElision::May && floatAttr.getType().isF64() &&
2291  !printedHex)
2292  return;
2293 
2294  } else if (auto strAttr = llvm::dyn_cast<StringAttr>(attr)) {
2295  printEscapedString(strAttr.getValue());
2296 
2297  } else if (auto arrayAttr = llvm::dyn_cast<ArrayAttr>(attr)) {
2298  os << '[';
2299  interleaveComma(arrayAttr.getValue(), [&](Attribute attr) {
2300  printAttribute(attr, AttrTypeElision::May);
2301  });
2302  os << ']';
2303 
2304  } else if (auto affineMapAttr = llvm::dyn_cast<AffineMapAttr>(attr)) {
2305  os << "affine_map<";
2306  affineMapAttr.getValue().print(os);
2307  os << '>';
2308 
2309  // AffineMap always elides the type.
2310  return;
2311 
2312  } else if (auto integerSetAttr = llvm::dyn_cast<IntegerSetAttr>(attr)) {
2313  os << "affine_set<";
2314  integerSetAttr.getValue().print(os);
2315  os << '>';
2316 
2317  // IntegerSet always elides the type.
2318  return;
2319 
2320  } else if (auto typeAttr = llvm::dyn_cast<TypeAttr>(attr)) {
2321  printType(typeAttr.getValue());
2322 
2323  } else if (auto refAttr = llvm::dyn_cast<SymbolRefAttr>(attr)) {
2324  printSymbolReference(refAttr.getRootReference().getValue(), os);
2325  for (FlatSymbolRefAttr nestedRef : refAttr.getNestedReferences()) {
2326  os << "::";
2327  printSymbolReference(nestedRef.getValue(), os);
2328  }
2329 
2330  } else if (auto intOrFpEltAttr =
2331  llvm::dyn_cast<DenseIntOrFPElementsAttr>(attr)) {
2332  if (printerFlags.shouldElideElementsAttr(intOrFpEltAttr)) {
2333  printElidedElementsAttr(os);
2334  } else {
2335  os << "dense<";
2336  printDenseIntOrFPElementsAttr(intOrFpEltAttr, /*allowHex=*/true);
2337  os << '>';
2338  }
2339 
2340  } else if (auto strEltAttr = llvm::dyn_cast<DenseStringElementsAttr>(attr)) {
2341  if (printerFlags.shouldElideElementsAttr(strEltAttr)) {
2342  printElidedElementsAttr(os);
2343  } else {
2344  os << "dense<";
2345  printDenseStringElementsAttr(strEltAttr);
2346  os << '>';
2347  }
2348 
2349  } else if (auto sparseEltAttr = llvm::dyn_cast<SparseElementsAttr>(attr)) {
2350  if (printerFlags.shouldElideElementsAttr(sparseEltAttr.getIndices()) ||
2351  printerFlags.shouldElideElementsAttr(sparseEltAttr.getValues())) {
2352  printElidedElementsAttr(os);
2353  } else {
2354  os << "sparse<";
2355  DenseIntElementsAttr indices = sparseEltAttr.getIndices();
2356  if (indices.getNumElements() != 0) {
2357  printDenseIntOrFPElementsAttr(indices, /*allowHex=*/false);
2358  os << ", ";
2359  printDenseElementsAttr(sparseEltAttr.getValues(), /*allowHex=*/true);
2360  }
2361  os << '>';
2362  }
2363  } else if (auto stridedLayoutAttr = llvm::dyn_cast<StridedLayoutAttr>(attr)) {
2364  stridedLayoutAttr.print(os);
2365  } else if (auto denseArrayAttr = llvm::dyn_cast<DenseArrayAttr>(attr)) {
2366  os << "array<";
2367  printType(denseArrayAttr.getElementType());
2368  if (!denseArrayAttr.empty()) {
2369  os << ": ";
2370  printDenseArrayAttr(denseArrayAttr);
2371  }
2372  os << ">";
2373  return;
2374  } else if (auto resourceAttr =
2375  llvm::dyn_cast<DenseResourceElementsAttr>(attr)) {
2376  os << "dense_resource<";
2377  printResourceHandle(resourceAttr.getRawHandle());
2378  os << ">";
2379  } else if (auto locAttr = llvm::dyn_cast<LocationAttr>(attr)) {
2380  printLocation(locAttr);
2381  } else {
2382  llvm::report_fatal_error("Unknown builtin attribute");
2383  }
2384  // Don't print the type if we must elide it, or if it is a None type.
2385  if (typeElision != AttrTypeElision::Must) {
2386  if (auto typedAttr = llvm::dyn_cast<TypedAttr>(attr)) {
2387  Type attrType = typedAttr.getType();
2388  if (!llvm::isa<NoneType>(attrType)) {
2389  os << " : ";
2390  printType(attrType);
2391  }
2392  }
2393  }
2394 }
2395 
2396 /// Print the integer element of a DenseElementsAttr.
2397 static void printDenseIntElement(const APInt &value, raw_ostream &os,
2398  Type type) {
2399  if (type.isInteger(1))
2400  os << (value.getBoolValue() ? "true" : "false");
2401  else
2402  value.print(os, !type.isUnsignedInteger());
2403 }
2404 
2405 static void
2406 printDenseElementsAttrImpl(bool isSplat, ShapedType type, raw_ostream &os,
2407  function_ref<void(unsigned)> printEltFn) {
2408  // Special case for 0-d and splat tensors.
2409  if (isSplat)
2410  return printEltFn(0);
2411 
2412  // Special case for degenerate tensors.
2413  auto numElements = type.getNumElements();
2414  if (numElements == 0)
2415  return;
2416 
2417  // We use a mixed-radix counter to iterate through the shape. When we bump a
2418  // non-least-significant digit, we emit a close bracket. When we next emit an
2419  // element we re-open all closed brackets.
2420 
2421  // The mixed-radix counter, with radices in 'shape'.
2422  int64_t rank = type.getRank();
2423  SmallVector<unsigned, 4> counter(rank, 0);
2424  // The number of brackets that have been opened and not closed.
2425  unsigned openBrackets = 0;
2426 
2427  auto shape = type.getShape();
2428  auto bumpCounter = [&] {
2429  // Bump the least significant digit.
2430  ++counter[rank - 1];
2431  // Iterate backwards bubbling back the increment.
2432  for (unsigned i = rank - 1; i > 0; --i)
2433  if (counter[i] >= shape[i]) {
2434  // Index 'i' is rolled over. Bump (i-1) and close a bracket.
2435  counter[i] = 0;
2436  ++counter[i - 1];
2437  --openBrackets;
2438  os << ']';
2439  }
2440  };
2441 
2442  for (unsigned idx = 0, e = numElements; idx != e; ++idx) {
2443  if (idx != 0)
2444  os << ", ";
2445  while (openBrackets++ < rank)
2446  os << '[';
2447  openBrackets = rank;
2448  printEltFn(idx);
2449  bumpCounter();
2450  }
2451  while (openBrackets-- > 0)
2452  os << ']';
2453 }
2454 
2455 void AsmPrinter::Impl::printDenseElementsAttr(DenseElementsAttr attr,
2456  bool allowHex) {
2457  if (auto stringAttr = llvm::dyn_cast<DenseStringElementsAttr>(attr))
2458  return printDenseStringElementsAttr(stringAttr);
2459 
2460  printDenseIntOrFPElementsAttr(llvm::cast<DenseIntOrFPElementsAttr>(attr),
2461  allowHex);
2462 }
2463 
2464 void AsmPrinter::Impl::printDenseIntOrFPElementsAttr(
2465  DenseIntOrFPElementsAttr attr, bool allowHex) {
2466  auto type = attr.getType();
2467  auto elementType = type.getElementType();
2468 
2469  // Check to see if we should format this attribute as a hex string.
2470  if (allowHex && printerFlags.shouldPrintElementsAttrWithHex(attr)) {
2471  ArrayRef<char> rawData = attr.getRawData();
2472  if (llvm::endianness::native == llvm::endianness::big) {
2473  // Convert endianess in big-endian(BE) machines. `rawData` is BE in BE
2474  // machines. It is converted here to print in LE format.
2475  SmallVector<char, 64> outDataVec(rawData.size());
2476  MutableArrayRef<char> convRawData(outDataVec);
2477  DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
2478  rawData, convRawData, type);
2479  printHexString(convRawData);
2480  } else {
2481  printHexString(rawData);
2482  }
2483 
2484  return;
2485  }
2486 
2487  if (ComplexType complexTy = llvm::dyn_cast<ComplexType>(elementType)) {
2488  Type complexElementType = complexTy.getElementType();
2489  // Note: The if and else below had a common lambda function which invoked
2490  // printDenseElementsAttrImpl. This lambda was hitting a bug in gcc 9.1,9.2
2491  // and hence was replaced.
2492  if (llvm::isa<IntegerType>(complexElementType)) {
2493  auto valueIt = attr.value_begin<std::complex<APInt>>();
2494  printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2495  auto complexValue = *(valueIt + index);
2496  os << "(";
2497  printDenseIntElement(complexValue.real(), os, complexElementType);
2498  os << ",";
2499  printDenseIntElement(complexValue.imag(), os, complexElementType);
2500  os << ")";
2501  });
2502  } else {
2503  auto valueIt = attr.value_begin<std::complex<APFloat>>();
2504  printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2505  auto complexValue = *(valueIt + index);
2506  os << "(";
2507  printFloatValue(complexValue.real(), os);
2508  os << ",";
2509  printFloatValue(complexValue.imag(), os);
2510  os << ")";
2511  });
2512  }
2513  } else if (elementType.isIntOrIndex()) {
2514  auto valueIt = attr.value_begin<APInt>();
2515  printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2516  printDenseIntElement(*(valueIt + index), os, elementType);
2517  });
2518  } else {
2519  assert(llvm::isa<FloatType>(elementType) && "unexpected element type");
2520  auto valueIt = attr.value_begin<APFloat>();
2521  printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2522  printFloatValue(*(valueIt + index), os);
2523  });
2524  }
2525 }
2526 
2527 void AsmPrinter::Impl::printDenseStringElementsAttr(
2528  DenseStringElementsAttr attr) {
2529  ArrayRef<StringRef> data = attr.getRawStringData();
2530  auto printFn = [&](unsigned index) { printEscapedString(data[index]); };
2531  printDenseElementsAttrImpl(attr.isSplat(), attr.getType(), os, printFn);
2532 }
2533 
2534 void AsmPrinter::Impl::printDenseArrayAttr(DenseArrayAttr attr) {
2535  Type type = attr.getElementType();
2536  unsigned bitwidth = type.isInteger(1) ? 8 : type.getIntOrFloatBitWidth();
2537  unsigned byteSize = bitwidth / 8;
2538  ArrayRef<char> data = attr.getRawData();
2539 
2540  auto printElementAt = [&](unsigned i) {
2541  APInt value(bitwidth, 0);
2542  if (bitwidth) {
2543  llvm::LoadIntFromMemory(
2544  value, reinterpret_cast<const uint8_t *>(data.begin() + byteSize * i),
2545  byteSize);
2546  }
2547  // Print the data as-is or as a float.
2548  if (type.isIntOrIndex()) {
2549  printDenseIntElement(value, getStream(), type);
2550  } else {
2551  APFloat fltVal(llvm::cast<FloatType>(type).getFloatSemantics(), value);
2552  printFloatValue(fltVal, getStream());
2553  }
2554  };
2555  llvm::interleaveComma(llvm::seq<unsigned>(0, attr.size()), getStream(),
2556  printElementAt);
2557 }
2558 
2559 void AsmPrinter::Impl::printType(Type type) {
2560  if (!type) {
2561  os << "<<NULL TYPE>>";
2562  return;
2563  }
2564 
2565  // Try to print an alias for this type.
2566  if (succeeded(printAlias(type)))
2567  return;
2568  return printTypeImpl(type);
2569 }
2570 
2571 void AsmPrinter::Impl::printTypeImpl(Type type) {
2572  TypeSwitch<Type>(type)
2573  .Case<OpaqueType>([&](OpaqueType opaqueTy) {
2574  printDialectSymbol(os, "!", opaqueTy.getDialectNamespace(),
2575  opaqueTy.getTypeData());
2576  })
2577  .Case<IndexType>([&](Type) { os << "index"; })
2578  .Case<Float8E5M2Type>([&](Type) { os << "f8E5M2"; })
2579  .Case<Float8E4M3Type>([&](Type) { os << "f8E4M3"; })
2580  .Case<Float8E4M3FNType>([&](Type) { os << "f8E4M3FN"; })
2581  .Case<Float8E5M2FNUZType>([&](Type) { os << "f8E5M2FNUZ"; })
2582  .Case<Float8E4M3FNUZType>([&](Type) { os << "f8E4M3FNUZ"; })
2583  .Case<Float8E4M3B11FNUZType>([&](Type) { os << "f8E4M3B11FNUZ"; })
2584  .Case<BFloat16Type>([&](Type) { os << "bf16"; })
2585  .Case<Float16Type>([&](Type) { os << "f16"; })
2586  .Case<FloatTF32Type>([&](Type) { os << "tf32"; })
2587  .Case<Float32Type>([&](Type) { os << "f32"; })
2588  .Case<Float64Type>([&](Type) { os << "f64"; })
2589  .Case<Float80Type>([&](Type) { os << "f80"; })
2590  .Case<Float128Type>([&](Type) { os << "f128"; })
2591  .Case<IntegerType>([&](IntegerType integerTy) {
2592  if (integerTy.isSigned())
2593  os << 's';
2594  else if (integerTy.isUnsigned())
2595  os << 'u';
2596  os << 'i' << integerTy.getWidth();
2597  })
2598  .Case<FunctionType>([&](FunctionType funcTy) {
2599  os << '(';
2600  interleaveComma(funcTy.getInputs(), [&](Type ty) { printType(ty); });
2601  os << ") -> ";
2602  ArrayRef<Type> results = funcTy.getResults();
2603  if (results.size() == 1 && !llvm::isa<FunctionType>(results[0])) {
2604  printType(results[0]);
2605  } else {
2606  os << '(';
2607  interleaveComma(results, [&](Type ty) { printType(ty); });
2608  os << ')';
2609  }
2610  })
2611  .Case<VectorType>([&](VectorType vectorTy) {
2612  auto scalableDims = vectorTy.getScalableDims();
2613  os << "vector<";
2614  auto vShape = vectorTy.getShape();
2615  unsigned lastDim = vShape.size();
2616  unsigned dimIdx = 0;
2617  for (dimIdx = 0; dimIdx < lastDim; dimIdx++) {
2618  if (!scalableDims.empty() && scalableDims[dimIdx])
2619  os << '[';
2620  os << vShape[dimIdx];
2621  if (!scalableDims.empty() && scalableDims[dimIdx])
2622  os << ']';
2623  os << 'x';
2624  }
2625  printType(vectorTy.getElementType());
2626  os << '>';
2627  })
2628  .Case<RankedTensorType>([&](RankedTensorType tensorTy) {
2629  os << "tensor<";
2630  printDimensionList(tensorTy.getShape());
2631  if (!tensorTy.getShape().empty())
2632  os << 'x';
2633  printType(tensorTy.getElementType());
2634  // Only print the encoding attribute value if set.
2635  if (tensorTy.getEncoding()) {
2636  os << ", ";
2637  printAttribute(tensorTy.getEncoding());
2638  }
2639  os << '>';
2640  })
2641  .Case<UnrankedTensorType>([&](UnrankedTensorType tensorTy) {
2642  os << "tensor<*x";
2643  printType(tensorTy.getElementType());
2644  os << '>';
2645  })
2646  .Case<MemRefType>([&](MemRefType memrefTy) {
2647  os << "memref<";
2648  printDimensionList(memrefTy.getShape());
2649  if (!memrefTy.getShape().empty())
2650  os << 'x';
2651  printType(memrefTy.getElementType());
2652  MemRefLayoutAttrInterface layout = memrefTy.getLayout();
2653  if (!llvm::isa<AffineMapAttr>(layout) || !layout.isIdentity()) {
2654  os << ", ";
2655  printAttribute(memrefTy.getLayout(), AttrTypeElision::May);
2656  }
2657  // Only print the memory space if it is the non-default one.
2658  if (memrefTy.getMemorySpace()) {
2659  os << ", ";
2660  printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2661  }
2662  os << '>';
2663  })
2664  .Case<UnrankedMemRefType>([&](UnrankedMemRefType memrefTy) {
2665  os << "memref<*x";
2666  printType(memrefTy.getElementType());
2667  // Only print the memory space if it is the non-default one.
2668  if (memrefTy.getMemorySpace()) {
2669  os << ", ";
2670  printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2671  }
2672  os << '>';
2673  })
2674  .Case<ComplexType>([&](ComplexType complexTy) {
2675  os << "complex<";
2676  printType(complexTy.getElementType());
2677  os << '>';
2678  })
2679  .Case<TupleType>([&](TupleType tupleTy) {
2680  os << "tuple<";
2681  interleaveComma(tupleTy.getTypes(),
2682  [&](Type type) { printType(type); });
2683  os << '>';
2684  })
2685  .Case<NoneType>([&](Type) { os << "none"; })
2686  .Default([&](Type type) { return printDialectType(type); });
2687 }
2688 
2689 void AsmPrinter::Impl::printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
2690  ArrayRef<StringRef> elidedAttrs,
2691  bool withKeyword) {
2692  // If there are no attributes, then there is nothing to be done.
2693  if (attrs.empty())
2694  return;
2695 
2696  // Functor used to print a filtered attribute list.
2697  auto printFilteredAttributesFn = [&](auto filteredAttrs) {
2698  // Print the 'attributes' keyword if necessary.
2699  if (withKeyword)
2700  os << " attributes";
2701 
2702  // Otherwise, print them all out in braces.
2703  os << " {";
2704  interleaveComma(filteredAttrs,
2705  [&](NamedAttribute attr) { printNamedAttribute(attr); });
2706  os << '}';
2707  };
2708 
2709  // If no attributes are elided, we can directly print with no filtering.
2710  if (elidedAttrs.empty())
2711  return printFilteredAttributesFn(attrs);
2712 
2713  // Otherwise, filter out any attributes that shouldn't be included.
2714  llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
2715  elidedAttrs.end());
2716  auto filteredAttrs = llvm::make_filter_range(attrs, [&](NamedAttribute attr) {
2717  return !elidedAttrsSet.contains(attr.getName().strref());
2718  });
2719  if (!filteredAttrs.empty())
2720  printFilteredAttributesFn(filteredAttrs);
2721 }
2722 void AsmPrinter::Impl::printNamedAttribute(NamedAttribute attr) {
2723  // Print the name without quotes if possible.
2724  ::printKeywordOrString(attr.getName().strref(), os);
2725 
2726  // Pretty printing elides the attribute value for unit attributes.
2727  if (llvm::isa<UnitAttr>(attr.getValue()))
2728  return;
2729 
2730  os << " = ";
2731  printAttribute(attr.getValue());
2732 }
2733 
2734 void AsmPrinter::Impl::printDialectAttribute(Attribute attr) {
2735  auto &dialect = attr.getDialect();
2736 
2737  // Ask the dialect to serialize the attribute to a string.
2738  std::string attrName;
2739  {
2740  llvm::raw_string_ostream attrNameStr(attrName);
2741  Impl subPrinter(attrNameStr, state);
2742  DialectAsmPrinter printer(subPrinter);
2743  dialect.printAttribute(attr, printer);
2744  }
2745  printDialectSymbol(os, "#", dialect.getNamespace(), attrName);
2746 }
2747 
2748 void AsmPrinter::Impl::printDialectType(Type type) {
2749  auto &dialect = type.getDialect();
2750 
2751  // Ask the dialect to serialize the type to a string.
2752  std::string typeName;
2753  {
2754  llvm::raw_string_ostream typeNameStr(typeName);
2755  Impl subPrinter(typeNameStr, state);
2756  DialectAsmPrinter printer(subPrinter);
2757  dialect.printType(type, printer);
2758  }
2759  printDialectSymbol(os, "!", dialect.getNamespace(), typeName);
2760 }
2761 
2762 void AsmPrinter::Impl::printEscapedString(StringRef str) {
2763  os << "\"";
2764  llvm::printEscapedString(str, os);
2765  os << "\"";
2766 }
2767 
2769  os << "\"0x" << llvm::toHex(str) << "\"";
2770 }
2772  printHexString(StringRef(data.data(), data.size()));
2773 }
2774 
2775 LogicalResult AsmPrinter::Impl::pushCyclicPrinting(const void *opaquePointer) {
2776  return state.pushCyclicPrinting(opaquePointer);
2777 }
2778 
2779 void AsmPrinter::Impl::popCyclicPrinting() { state.popCyclicPrinting(); }
2780 
2782  detail::printDimensionList(os, shape);
2783 }
2784 
2785 //===--------------------------------------------------------------------===//
2786 // AsmPrinter
2787 //===--------------------------------------------------------------------===//
2788 
2789 AsmPrinter::~AsmPrinter() = default;
2790 
2791 raw_ostream &AsmPrinter::getStream() const {
2792  assert(impl && "expected AsmPrinter::getStream to be overriden");
2793  return impl->getStream();
2794 }
2795 
2796 /// Print the given floating point value in a stablized form.
2797 void AsmPrinter::printFloat(const APFloat &value) {
2798  assert(impl && "expected AsmPrinter::printFloat to be overriden");
2799  printFloatValue(value, impl->getStream());
2800 }
2801 
2803  assert(impl && "expected AsmPrinter::printType to be overriden");
2804  impl->printType(type);
2805 }
2806 
2808  assert(impl && "expected AsmPrinter::printAttribute to be overriden");
2809  impl->printAttribute(attr);
2810 }
2811 
2812 LogicalResult AsmPrinter::printAlias(Attribute attr) {
2813  assert(impl && "expected AsmPrinter::printAlias to be overriden");
2814  return impl->printAlias(attr);
2815 }
2816 
2817 LogicalResult AsmPrinter::printAlias(Type type) {
2818  assert(impl && "expected AsmPrinter::printAlias to be overriden");
2819  return impl->printAlias(type);
2820 }
2821 
2823  assert(impl &&
2824  "expected AsmPrinter::printAttributeWithoutType to be overriden");
2825  impl->printAttribute(attr, Impl::AttrTypeElision::Must);
2826 }
2827 
2828 void AsmPrinter::printKeywordOrString(StringRef keyword) {
2829  assert(impl && "expected AsmPrinter::printKeywordOrString to be overriden");
2830  ::printKeywordOrString(keyword, impl->getStream());
2831 }
2832 
2833 void AsmPrinter::printString(StringRef keyword) {
2834  assert(impl && "expected AsmPrinter::printString to be overriden");
2835  *this << '"';
2836  printEscapedString(keyword, getStream());
2837  *this << '"';
2838 }
2839 
2840 void AsmPrinter::printSymbolName(StringRef symbolRef) {
2841  assert(impl && "expected AsmPrinter::printSymbolName to be overriden");
2842  ::printSymbolReference(symbolRef, impl->getStream());
2843 }
2844 
2846  assert(impl && "expected AsmPrinter::printResourceHandle to be overriden");
2847  impl->printResourceHandle(resource);
2848 }
2849 
2852 }
2853 
2854 LogicalResult AsmPrinter::pushCyclicPrinting(const void *opaquePointer) {
2855  return impl->pushCyclicPrinting(opaquePointer);
2856 }
2857 
2858 void AsmPrinter::popCyclicPrinting() { impl->popCyclicPrinting(); }
2859 
2860 //===----------------------------------------------------------------------===//
2861 // Affine expressions and maps
2862 //===----------------------------------------------------------------------===//
2863 
2865  AffineExpr expr, function_ref<void(unsigned, bool)> printValueName) {
2866  printAffineExprInternal(expr, BindingStrength::Weak, printValueName);
2867 }
2868 
2870  AffineExpr expr, BindingStrength enclosingTightness,
2871  function_ref<void(unsigned, bool)> printValueName) {
2872  const char *binopSpelling = nullptr;
2873  switch (expr.getKind()) {
2874  case AffineExprKind::SymbolId: {
2875  unsigned pos = cast<AffineSymbolExpr>(expr).getPosition();
2876  if (printValueName)
2877  printValueName(pos, /*isSymbol=*/true);
2878  else
2879  os << 's' << pos;
2880  return;
2881  }
2882  case AffineExprKind::DimId: {
2883  unsigned pos = cast<AffineDimExpr>(expr).getPosition();
2884  if (printValueName)
2885  printValueName(pos, /*isSymbol=*/false);
2886  else
2887  os << 'd' << pos;
2888  return;
2889  }
2891  os << cast<AffineConstantExpr>(expr).getValue();
2892  return;
2893  case AffineExprKind::Add:
2894  binopSpelling = " + ";
2895  break;
2896  case AffineExprKind::Mul:
2897  binopSpelling = " * ";
2898  break;
2900  binopSpelling = " floordiv ";
2901  break;
2903  binopSpelling = " ceildiv ";
2904  break;
2905  case AffineExprKind::Mod:
2906  binopSpelling = " mod ";
2907  break;
2908  }
2909 
2910  auto binOp = cast<AffineBinaryOpExpr>(expr);
2911  AffineExpr lhsExpr = binOp.getLHS();
2912  AffineExpr rhsExpr = binOp.getRHS();
2913 
2914  // Handle tightly binding binary operators.
2915  if (binOp.getKind() != AffineExprKind::Add) {
2916  if (enclosingTightness == BindingStrength::Strong)
2917  os << '(';
2918 
2919  // Pretty print multiplication with -1.
2920  auto rhsConst = dyn_cast<AffineConstantExpr>(rhsExpr);
2921  if (rhsConst && binOp.getKind() == AffineExprKind::Mul &&
2922  rhsConst.getValue() == -1) {
2923  os << "-";
2924  printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
2925  if (enclosingTightness == BindingStrength::Strong)
2926  os << ')';
2927  return;
2928  }
2929 
2930  printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
2931 
2932  os << binopSpelling;
2933  printAffineExprInternal(rhsExpr, BindingStrength::Strong, printValueName);
2934 
2935  if (enclosingTightness == BindingStrength::Strong)
2936  os << ')';
2937  return;
2938  }
2939 
2940  // Print out special "pretty" forms for add.
2941  if (enclosingTightness == BindingStrength::Strong)
2942  os << '(';
2943 
2944  // Pretty print addition to a product that has a negative operand as a
2945  // subtraction.
2946  if (auto rhs = dyn_cast<AffineBinaryOpExpr>(rhsExpr)) {
2947  if (rhs.getKind() == AffineExprKind::Mul) {
2948  AffineExpr rrhsExpr = rhs.getRHS();
2949  if (auto rrhs = dyn_cast<AffineConstantExpr>(rrhsExpr)) {
2950  if (rrhs.getValue() == -1) {
2951  printAffineExprInternal(lhsExpr, BindingStrength::Weak,
2952  printValueName);
2953  os << " - ";
2954  if (rhs.getLHS().getKind() == AffineExprKind::Add) {
2955  printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
2956  printValueName);
2957  } else {
2958  printAffineExprInternal(rhs.getLHS(), BindingStrength::Weak,
2959  printValueName);
2960  }
2961 
2962  if (enclosingTightness == BindingStrength::Strong)
2963  os << ')';
2964  return;
2965  }
2966 
2967  if (rrhs.getValue() < -1) {
2968  printAffineExprInternal(lhsExpr, BindingStrength::Weak,
2969  printValueName);
2970  os << " - ";
2971  printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
2972  printValueName);
2973  os << " * " << -rrhs.getValue();
2974  if (enclosingTightness == BindingStrength::Strong)
2975  os << ')';
2976  return;
2977  }
2978  }
2979  }
2980  }
2981 
2982  // Pretty print addition to a negative number as a subtraction.
2983  if (auto rhsConst = dyn_cast<AffineConstantExpr>(rhsExpr)) {
2984  if (rhsConst.getValue() < 0) {
2985  printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
2986  os << " - " << -rhsConst.getValue();
2987  if (enclosingTightness == BindingStrength::Strong)
2988  os << ')';
2989  return;
2990  }
2991  }
2992 
2993  printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
2994 
2995  os << " + ";
2996  printAffineExprInternal(rhsExpr, BindingStrength::Weak, printValueName);
2997 
2998  if (enclosingTightness == BindingStrength::Strong)
2999  os << ')';
3000 }
3001 
3003  printAffineExprInternal(expr, BindingStrength::Weak);
3004  isEq ? os << " == 0" : os << " >= 0";
3005 }
3006 
3008  // Dimension identifiers.
3009  os << '(';
3010  for (int i = 0; i < (int)map.getNumDims() - 1; ++i)
3011  os << 'd' << i << ", ";
3012  if (map.getNumDims() >= 1)
3013  os << 'd' << map.getNumDims() - 1;
3014  os << ')';
3015 
3016  // Symbolic identifiers.
3017  if (map.getNumSymbols() != 0) {
3018  os << '[';
3019  for (unsigned i = 0; i < map.getNumSymbols() - 1; ++i)
3020  os << 's' << i << ", ";
3021  if (map.getNumSymbols() >= 1)
3022  os << 's' << map.getNumSymbols() - 1;
3023  os << ']';
3024  }
3025 
3026  // Result affine expressions.
3027  os << " -> (";
3028  interleaveComma(map.getResults(),
3029  [&](AffineExpr expr) { printAffineExpr(expr); });
3030  os << ')';
3031 }
3032 
3034  // Dimension identifiers.
3035  os << '(';
3036  for (unsigned i = 1; i < set.getNumDims(); ++i)
3037  os << 'd' << i - 1 << ", ";
3038  if (set.getNumDims() >= 1)
3039  os << 'd' << set.getNumDims() - 1;
3040  os << ')';
3041 
3042  // Symbolic identifiers.
3043  if (set.getNumSymbols() != 0) {
3044  os << '[';
3045  for (unsigned i = 0; i < set.getNumSymbols() - 1; ++i)
3046  os << 's' << i << ", ";
3047  if (set.getNumSymbols() >= 1)
3048  os << 's' << set.getNumSymbols() - 1;
3049  os << ']';
3050  }
3051 
3052  // Print constraints.
3053  os << " : (";
3054  int numConstraints = set.getNumConstraints();
3055  for (int i = 1; i < numConstraints; ++i) {
3056  printAffineConstraint(set.getConstraint(i - 1), set.isEq(i - 1));
3057  os << ", ";
3058  }
3059  if (numConstraints >= 1)
3060  printAffineConstraint(set.getConstraint(numConstraints - 1),
3061  set.isEq(numConstraints - 1));
3062  os << ')';
3063 }
3064 
3065 //===----------------------------------------------------------------------===//
3066 // OperationPrinter
3067 //===----------------------------------------------------------------------===//
3068 
3069 namespace {
3070 /// This class contains the logic for printing operations, regions, and blocks.
3071 class OperationPrinter : public AsmPrinter::Impl, private OpAsmPrinter {
3072 public:
3073  using Impl = AsmPrinter::Impl;
3074  using Impl::printType;
3075 
3076  explicit OperationPrinter(raw_ostream &os, AsmStateImpl &state)
3077  : Impl(os, state), OpAsmPrinter(static_cast<Impl &>(*this)) {}
3078 
3079  /// Print the given top-level operation.
3080  void printTopLevelOperation(Operation *op);
3081 
3082  /// Print the given operation, including its left-hand side and its right-hand
3083  /// side, with its indent and location.
3084  void printFullOpWithIndentAndLoc(Operation *op);
3085  /// Print the given operation, including its left-hand side and its right-hand
3086  /// side, but not including indentation and location.
3087  void printFullOp(Operation *op);
3088  /// Print the right-hand size of the given operation in the custom or generic
3089  /// form.
3090  void printCustomOrGenericOp(Operation *op) override;
3091  /// Print the right-hand side of the given operation in the generic form.
3092  void printGenericOp(Operation *op, bool printOpName) override;
3093 
3094  /// Print the name of the given block.
3095  void printBlockName(Block *block);
3096 
3097  /// Print the given block. If 'printBlockArgs' is false, the arguments of the
3098  /// block are not printed. If 'printBlockTerminator' is false, the terminator
3099  /// operation of the block is not printed.
3100  void print(Block *block, bool printBlockArgs = true,
3101  bool printBlockTerminator = true);
3102 
3103  /// Print the ID of the given value, optionally with its result number.
3104  void printValueID(Value value, bool printResultNo = true,
3105  raw_ostream *streamOverride = nullptr) const;
3106 
3107  /// Print the ID of the given operation.
3108  void printOperationID(Operation *op,
3109  raw_ostream *streamOverride = nullptr) const;
3110 
3111  //===--------------------------------------------------------------------===//
3112  // OpAsmPrinter methods
3113  //===--------------------------------------------------------------------===//
3114 
3115  /// Print a loc(...) specifier if printing debug info is enabled. Locations
3116  /// may be deferred with an alias.
3117  void printOptionalLocationSpecifier(Location loc) override {
3118  printTrailingLocation(loc);
3119  }
3120 
3121  /// Print a newline and indent the printer to the start of the current
3122  /// operation.
3123  void printNewline() override {
3124  os << newLine;
3125  os.indent(currentIndent);
3126  }
3127 
3128  /// Increase indentation.
3129  void increaseIndent() override { currentIndent += indentWidth; }
3130 
3131  /// Decrease indentation.
3132  void decreaseIndent() override { currentIndent -= indentWidth; }
3133 
3134  /// Print a block argument in the usual format of:
3135  /// %ssaName : type {attr1=42} loc("here")
3136  /// where location printing is controlled by the standard internal option.
3137  /// You may pass omitType=true to not print a type, and pass an empty
3138  /// attribute list if you don't care for attributes.
3139  void printRegionArgument(BlockArgument arg,
3140  ArrayRef<NamedAttribute> argAttrs = {},
3141  bool omitType = false) override;
3142 
3143  /// Print the ID for the given value.
3144  void printOperand(Value value) override { printValueID(value); }
3145  void printOperand(Value value, raw_ostream &os) override {
3146  printValueID(value, /*printResultNo=*/true, &os);
3147  }
3148 
3149  /// Print an optional attribute dictionary with a given set of elided values.
3150  void printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
3151  ArrayRef<StringRef> elidedAttrs = {}) override {
3152  Impl::printOptionalAttrDict(attrs, elidedAttrs);
3153  }
3154  void printOptionalAttrDictWithKeyword(
3156  ArrayRef<StringRef> elidedAttrs = {}) override {
3157  Impl::printOptionalAttrDict(attrs, elidedAttrs,
3158  /*withKeyword=*/true);
3159  }
3160 
3161  /// Print the given successor.
3162  void printSuccessor(Block *successor) override;
3163 
3164  /// Print an operation successor with the operands used for the block
3165  /// arguments.
3166  void printSuccessorAndUseList(Block *successor,
3167  ValueRange succOperands) override;
3168 
3169  /// Print the given region.
3170  void printRegion(Region &region, bool printEntryBlockArgs,
3171  bool printBlockTerminators, bool printEmptyBlock) override;
3172 
3173  /// Renumber the arguments for the specified region to the same names as the
3174  /// SSA values in namesToUse. This may only be used for IsolatedFromAbove
3175  /// operations. If any entry in namesToUse is null, the corresponding
3176  /// argument name is left alone.
3177  void shadowRegionArgs(Region &region, ValueRange namesToUse) override {
3178  state.getSSANameState().shadowRegionArgs(region, namesToUse);
3179  }
3180 
3181  /// Print the given affine map with the symbol and dimension operands printed
3182  /// inline with the map.
3183  void printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3184  ValueRange operands) override;
3185 
3186  /// Print the given affine expression with the symbol and dimension operands
3187  /// printed inline with the expression.
3188  void printAffineExprOfSSAIds(AffineExpr expr, ValueRange dimOperands,
3189  ValueRange symOperands) override;
3190 
3191  /// Print users of this operation or id of this operation if it has no result.
3192  void printUsersComment(Operation *op);
3193 
3194  /// Print users of this block arg.
3195  void printUsersComment(BlockArgument arg);
3196 
3197  /// Print the users of a value.
3198  void printValueUsers(Value value);
3199 
3200  /// Print either the ids of the result values or the id of the operation if
3201  /// the operation has no results.
3202  void printUserIDs(Operation *user, bool prefixComma = false);
3203 
3204 private:
3205  /// This class represents a resource builder implementation for the MLIR
3206  /// textual assembly format.
3207  class ResourceBuilder : public AsmResourceBuilder {
3208  public:
3209  using ValueFn = function_ref<void(raw_ostream &)>;
3210  using PrintFn = function_ref<void(StringRef, ValueFn)>;
3211 
3212  ResourceBuilder(PrintFn printFn) : printFn(printFn) {}
3213  ~ResourceBuilder() override = default;
3214 
3215  void buildBool(StringRef key, bool data) final {
3216  printFn(key, [&](raw_ostream &os) { os << (data ? "true" : "false"); });
3217  }
3218 
3219  void buildString(StringRef key, StringRef data) final {
3220  printFn(key, [&](raw_ostream &os) {
3221  os << "\"";
3222  llvm::printEscapedString(data, os);
3223  os << "\"";
3224  });
3225  }
3226 
3227  void buildBlob(StringRef key, ArrayRef<char> data,
3228  uint32_t dataAlignment) final {
3229  printFn(key, [&](raw_ostream &os) {
3230  // Store the blob in a hex string containing the alignment and the data.
3231  llvm::support::ulittle32_t dataAlignmentLE(dataAlignment);
3232  os << "\"0x"
3233  << llvm::toHex(StringRef(reinterpret_cast<char *>(&dataAlignmentLE),
3234  sizeof(dataAlignment)))
3235  << llvm::toHex(StringRef(data.data(), data.size())) << "\"";
3236  });
3237  }
3238 
3239  private:
3240  PrintFn printFn;
3241  };
3242 
3243  /// Print the metadata dictionary for the file, eliding it if it is empty.
3244  void printFileMetadataDictionary(Operation *op);
3245 
3246  /// Print the resource sections for the file metadata dictionary.
3247  /// `checkAddMetadataDict` is used to indicate that metadata is going to be
3248  /// added, and the file metadata dictionary should be started if it hasn't
3249  /// yet.
3250  void printResourceFileMetadata(function_ref<void()> checkAddMetadataDict,
3251  Operation *op);
3252 
3253  // Contains the stack of default dialects to use when printing regions.
3254  // A new dialect is pushed to the stack before parsing regions nested under an
3255  // operation implementing `OpAsmOpInterface`, and popped when done. At the
3256  // top-level we start with "builtin" as the default, so that the top-level
3257  // `module` operation prints as-is.
3258  SmallVector<StringRef> defaultDialectStack{"builtin"};
3259 
3260  /// The number of spaces used for indenting nested operations.
3261  const static unsigned indentWidth = 2;
3262 
3263  // This is the current indentation level for nested structures.
3264  unsigned currentIndent = 0;
3265 };
3266 } // namespace
3267 
3268 void OperationPrinter::printTopLevelOperation(Operation *op) {
3269  // Output the aliases at the top level that can't be deferred.
3270  state.getAliasState().printNonDeferredAliases(*this, newLine);
3271 
3272  // Print the module.
3273  printFullOpWithIndentAndLoc(op);
3274  os << newLine;
3275 
3276  // Output the aliases at the top level that can be deferred.
3277  state.getAliasState().printDeferredAliases(*this, newLine);
3278 
3279  // Output any file level metadata.
3280  printFileMetadataDictionary(op);
3281 }
3282 
3283 void OperationPrinter::printFileMetadataDictionary(Operation *op) {
3284  bool sawMetadataEntry = false;
3285  auto checkAddMetadataDict = [&] {
3286  if (!std::exchange(sawMetadataEntry, true))
3287  os << newLine << "{-#" << newLine;
3288  };
3289 
3290  // Add the various types of metadata.
3291  printResourceFileMetadata(checkAddMetadataDict, op);
3292 
3293  // If the file dictionary exists, close it.
3294  if (sawMetadataEntry)
3295  os << newLine << "#-}" << newLine;
3296 }
3297 
3298 void OperationPrinter::printResourceFileMetadata(
3299  function_ref<void()> checkAddMetadataDict, Operation *op) {
3300  // Functor used to add data entries to the file metadata dictionary.
3301  bool hadResource = false;
3302  bool needResourceComma = false;
3303  bool needEntryComma = false;
3304  auto processProvider = [&](StringRef dictName, StringRef name, auto &provider,
3305  auto &&...providerArgs) {
3306  bool hadEntry = false;
3307  auto printFn = [&](StringRef key, ResourceBuilder::ValueFn valueFn) {
3308  checkAddMetadataDict();
3309 
3310  auto printFormatting = [&]() {
3311  // Emit the top-level resource entry if we haven't yet.
3312  if (!std::exchange(hadResource, true)) {
3313  if (needResourceComma)
3314  os << "," << newLine;
3315  os << " " << dictName << "_resources: {" << newLine;
3316  }
3317  // Emit the parent resource entry if we haven't yet.
3318  if (!std::exchange(hadEntry, true)) {
3319  if (needEntryComma)
3320  os << "," << newLine;
3321  os << " " << name << ": {" << newLine;
3322  } else {
3323  os << "," << newLine;
3324  }
3325  };
3326 
3327  std::optional<uint64_t> charLimit =
3328  printerFlags.getLargeResourceStringLimit();
3329  if (charLimit.has_value()) {
3330  std::string resourceStr;
3331  llvm::raw_string_ostream ss(resourceStr);
3332  valueFn(ss);
3333 
3334  // Only print entry if it's string is small enough
3335  if (resourceStr.size() > charLimit.value())
3336  return;
3337 
3338  printFormatting();
3339  os << " " << key << ": " << resourceStr;
3340  } else {
3341  printFormatting();
3342  os << " " << key << ": ";
3343  valueFn(os);
3344  }
3345  };
3346  ResourceBuilder entryBuilder(printFn);
3347  provider.buildResources(op, providerArgs..., entryBuilder);
3348 
3349  needEntryComma |= hadEntry;
3350  if (hadEntry)
3351  os << newLine << " }";
3352  };
3353 
3354  // Print the `dialect_resources` section if we have any dialects with
3355  // resources.
3356  for (const OpAsmDialectInterface &interface : state.getDialectInterfaces()) {
3357  auto &dialectResources = state.getDialectResources();
3358  StringRef name = interface.getDialect()->getNamespace();
3359  auto it = dialectResources.find(interface.getDialect());
3360  if (it != dialectResources.end())
3361  processProvider("dialect", name, interface, it->second);
3362  else
3363  processProvider("dialect", name, interface,
3365  }
3366  if (hadResource)
3367  os << newLine << " }";
3368 
3369  // Print the `external_resources` section if we have any external clients with
3370  // resources.
3371  needEntryComma = false;
3372  needResourceComma = hadResource;
3373  hadResource = false;
3374  for (const auto &printer : state.getResourcePrinters())
3375  processProvider("external", printer.getName(), printer);
3376  if (hadResource)
3377  os << newLine << " }";
3378 }
3379 
3380 /// Print a block argument in the usual format of:
3381 /// %ssaName : type {attr1=42} loc("here")
3382 /// where location printing is controlled by the standard internal option.
3383 /// You may pass omitType=true to not print a type, and pass an empty
3384 /// attribute list if you don't care for attributes.
3385 void OperationPrinter::printRegionArgument(BlockArgument arg,
3386  ArrayRef<NamedAttribute> argAttrs,
3387  bool omitType) {
3388  printOperand(arg);
3389  if (!omitType) {
3390  os << ": ";
3391  printType(arg.getType());
3392  }
3393  printOptionalAttrDict(argAttrs);
3394  // TODO: We should allow location aliases on block arguments.
3395  printTrailingLocation(arg.getLoc(), /*allowAlias*/ false);
3396 }
3397 
3398 void OperationPrinter::printFullOpWithIndentAndLoc(Operation *op) {
3399  // Track the location of this operation.
3400  state.registerOperationLocation(op, newLine.curLine, currentIndent);
3401 
3402  os.indent(currentIndent);
3403  printFullOp(op);
3404  printTrailingLocation(op->getLoc());
3405  if (printerFlags.shouldPrintValueUsers())
3406  printUsersComment(op);
3407 }
3408 
3409 void OperationPrinter::printFullOp(Operation *op) {
3410  if (size_t numResults = op->getNumResults()) {
3411  auto printResultGroup = [&](size_t resultNo, size_t resultCount) {
3412  printValueID(op->getResult(resultNo), /*printResultNo=*/false);
3413  if (resultCount > 1)
3414  os << ':' << resultCount;
3415  };
3416 
3417  // Check to see if this operation has multiple result groups.
3418  ArrayRef<int> resultGroups = state.getSSANameState().getOpResultGroups(op);
3419  if (!resultGroups.empty()) {
3420  // Interleave the groups excluding the last one, this one will be handled
3421  // separately.
3422  interleaveComma(llvm::seq<int>(0, resultGroups.size() - 1), [&](int i) {
3423  printResultGroup(resultGroups[i],
3424  resultGroups[i + 1] - resultGroups[i]);
3425  });
3426  os << ", ";
3427  printResultGroup(resultGroups.back(), numResults - resultGroups.back());
3428 
3429  } else {
3430  printResultGroup(/*resultNo=*/0, /*resultCount=*/numResults);
3431  }
3432 
3433  os << " = ";
3434  }
3435 
3436  printCustomOrGenericOp(op);
3437 }
3438 
3439 void OperationPrinter::printUsersComment(Operation *op) {
3440  unsigned numResults = op->getNumResults();
3441  if (!numResults && op->getNumOperands()) {
3442  os << " // id: ";
3443  printOperationID(op);
3444  } else if (numResults && op->use_empty()) {
3445  os << " // unused";
3446  } else if (numResults && !op->use_empty()) {
3447  // Print "user" if the operation has one result used to compute one other
3448  // result, or is used in one operation with no result.
3449  unsigned usedInNResults = 0;
3450  unsigned usedInNOperations = 0;
3452  for (Operation *user : op->getUsers()) {
3453  if (userSet.insert(user).second) {
3454  ++usedInNOperations;
3455  usedInNResults += user->getNumResults();
3456  }
3457  }
3458 
3459  // We already know that users is not empty.
3460  bool exactlyOneUniqueUse =
3461  usedInNResults <= 1 && usedInNOperations <= 1 && numResults == 1;
3462  os << " // " << (exactlyOneUniqueUse ? "user" : "users") << ": ";
3463  bool shouldPrintBrackets = numResults > 1;
3464  auto printOpResult = [&](OpResult opResult) {
3465  if (shouldPrintBrackets)
3466  os << "(";
3467  printValueUsers(opResult);
3468  if (shouldPrintBrackets)
3469  os << ")";
3470  };
3471 
3472  interleaveComma(op->getResults(), printOpResult);
3473  }
3474 }
3475 
3476 void OperationPrinter::printUsersComment(BlockArgument arg) {
3477  os << "// ";
3478  printValueID(arg);
3479  if (arg.use_empty()) {
3480  os << " is unused";
3481  } else {
3482  os << " is used by ";
3483  printValueUsers(arg);
3484  }
3485  os << newLine;
3486 }
3487 
3488 void OperationPrinter::printValueUsers(Value value) {
3489  if (value.use_empty())
3490  os << "unused";
3491 
3492  // One value might be used as the operand of an operation more than once.
3493  // Only print the operations results once in that case.
3495  for (auto [index, user] : enumerate(value.getUsers())) {
3496  if (userSet.insert(user).second)
3497  printUserIDs(user, index);
3498  }
3499 }
3500 
3501 void OperationPrinter::printUserIDs(Operation *user, bool prefixComma) {
3502  if (prefixComma)
3503  os << ", ";
3504 
3505  if (!user->getNumResults()) {
3506  printOperationID(user);
3507  } else {
3508  interleaveComma(user->getResults(),
3509  [this](Value result) { printValueID(result); });
3510  }
3511 }
3512 
3513 void OperationPrinter::printCustomOrGenericOp(Operation *op) {
3514  // If requested, always print the generic form.
3515  if (!printerFlags.shouldPrintGenericOpForm()) {
3516  // Check to see if this is a known operation. If so, use the registered
3517  // custom printer hook.
3518  if (auto opInfo = op->getRegisteredInfo()) {
3519  opInfo->printAssembly(op, *this, defaultDialectStack.back());
3520  return;
3521  }
3522  // Otherwise try to dispatch to the dialect, if available.
3523  if (Dialect *dialect = op->getDialect()) {
3524  if (auto opPrinter = dialect->getOperationPrinter(op)) {
3525  // Print the op name first.
3526  StringRef name = op->getName().getStringRef();
3527  // Only drop the default dialect prefix when it cannot lead to
3528  // ambiguities.
3529  if (name.count('.') == 1)
3530  name.consume_front((defaultDialectStack.back() + ".").str());
3531  os << name;
3532 
3533  // Print the rest of the op now.
3534  opPrinter(op, *this);
3535  return;
3536  }
3537  }
3538  }
3539 
3540  // Otherwise print with the generic assembly form.
3541  printGenericOp(op, /*printOpName=*/true);
3542 }
3543 
3544 void OperationPrinter::printGenericOp(Operation *op, bool printOpName) {
3545  if (printOpName)
3546  printEscapedString(op->getName().getStringRef());
3547  os << '(';
3548  interleaveComma(op->getOperands(), [&](Value value) { printValueID(value); });
3549  os << ')';
3550 
3551  // For terminators, print the list of successors and their operands.
3552  if (op->getNumSuccessors() != 0) {
3553  os << '[';
3554  interleaveComma(op->getSuccessors(),
3555  [&](Block *successor) { printBlockName(successor); });
3556  os << ']';
3557  }
3558 
3559  // Print the properties.
3560  if (Attribute prop = op->getPropertiesAsAttribute()) {
3561  os << " <";
3562  Impl::printAttribute(prop);
3563  os << '>';
3564  }
3565 
3566  // Print regions.
3567  if (op->getNumRegions() != 0) {
3568  os << " (";
3569  interleaveComma(op->getRegions(), [&](Region &region) {
3570  printRegion(region, /*printEntryBlockArgs=*/true,
3571  /*printBlockTerminators=*/true, /*printEmptyBlock=*/true);
3572  });
3573  os << ')';
3574  }
3575 
3576  printOptionalAttrDict(op->getPropertiesStorage()
3577  ? llvm::to_vector(op->getDiscardableAttrs())
3578  : op->getAttrs());
3579 
3580  // Print the type signature of the operation.
3581  os << " : ";
3582  printFunctionalType(op);
3583 }
3584 
3585 void OperationPrinter::printBlockName(Block *block) {
3586  os << state.getSSANameState().getBlockInfo(block).name;
3587 }
3588 
3589 void OperationPrinter::print(Block *block, bool printBlockArgs,
3590  bool printBlockTerminator) {
3591  // Print the block label and argument list if requested.
3592  if (printBlockArgs) {
3593  os.indent(currentIndent);
3594  printBlockName(block);
3595 
3596  // Print the argument list if non-empty.
3597  if (!block->args_empty()) {
3598  os << '(';
3599  interleaveComma(block->getArguments(), [&](BlockArgument arg) {
3600  printValueID(arg);
3601  os << ": ";
3602  printType(arg.getType());
3603  // TODO: We should allow location aliases on block arguments.
3604  printTrailingLocation(arg.getLoc(), /*allowAlias*/ false);
3605  });
3606  os << ')';
3607  }
3608  os << ':';
3609 
3610  // Print out some context information about the predecessors of this block.
3611  if (!block->getParent()) {
3612  os << " // block is not in a region!";
3613  } else if (block->hasNoPredecessors()) {
3614  if (!block->isEntryBlock())
3615  os << " // no predecessors";
3616  } else if (auto *pred = block->getSinglePredecessor()) {
3617  os << " // pred: ";
3618  printBlockName(pred);
3619  } else {
3620  // We want to print the predecessors in a stable order, not in
3621  // whatever order the use-list is in, so gather and sort them.
3622  SmallVector<BlockInfo, 4> predIDs;
3623  for (auto *pred : block->getPredecessors())
3624  predIDs.push_back(state.getSSANameState().getBlockInfo(pred));
3625  llvm::sort(predIDs, [](BlockInfo lhs, BlockInfo rhs) {
3626  return lhs.ordering < rhs.ordering;
3627  });
3628 
3629  os << " // " << predIDs.size() << " preds: ";
3630 
3631  interleaveComma(predIDs, [&](BlockInfo pred) { os << pred.name; });
3632  }
3633  os << newLine;
3634  }
3635 
3636  currentIndent += indentWidth;
3637 
3638  if (printerFlags.shouldPrintValueUsers()) {
3639  for (BlockArgument arg : block->getArguments()) {
3640  os.indent(currentIndent);
3641  printUsersComment(arg);
3642  }
3643  }
3644 
3645  bool hasTerminator =
3646  !block->empty() && block->back().hasTrait<OpTrait::IsTerminator>();
3647  auto range = llvm::make_range(
3648  block->begin(),
3649  std::prev(block->end(),
3650  (!hasTerminator || printBlockTerminator) ? 0 : 1));
3651  for (auto &op : range) {
3652  printFullOpWithIndentAndLoc(&op);
3653  os << newLine;
3654  }
3655  currentIndent -= indentWidth;
3656 }
3657 
3658 void OperationPrinter::printValueID(Value value, bool printResultNo,
3659  raw_ostream *streamOverride) const {
3660  state.getSSANameState().printValueID(value, printResultNo,
3661  streamOverride ? *streamOverride : os);
3662 }
3663 
3664 void OperationPrinter::printOperationID(Operation *op,
3665  raw_ostream *streamOverride) const {
3666  state.getSSANameState().printOperationID(op, streamOverride ? *streamOverride
3667  : os);
3668 }
3669 
3670 void OperationPrinter::printSuccessor(Block *successor) {
3671  printBlockName(successor);
3672 }
3673 
3674 void OperationPrinter::printSuccessorAndUseList(Block *successor,
3675  ValueRange succOperands) {
3676  printBlockName(successor);
3677  if (succOperands.empty())
3678  return;
3679 
3680  os << '(';
3681  interleaveComma(succOperands,
3682  [this](Value operand) { printValueID(operand); });
3683  os << " : ";
3684  interleaveComma(succOperands,
3685  [this](Value operand) { printType(operand.getType()); });
3686  os << ')';
3687 }
3688 
3689 void OperationPrinter::printRegion(Region &region, bool printEntryBlockArgs,
3690  bool printBlockTerminators,
3691  bool printEmptyBlock) {
3692  if (printerFlags.shouldSkipRegions()) {
3693  os << "{...}";
3694  return;
3695  }
3696  os << "{" << newLine;
3697  if (!region.empty()) {
3698  auto restoreDefaultDialect =
3699  llvm::make_scope_exit([&]() { defaultDialectStack.pop_back(); });
3700  if (auto iface = dyn_cast<OpAsmOpInterface>(region.getParentOp()))
3701  defaultDialectStack.push_back(iface.getDefaultDialect());
3702  else
3703  defaultDialectStack.push_back("");
3704 
3705  auto *entryBlock = &region.front();
3706  // Force printing the block header if printEmptyBlock is set and the block
3707  // is empty or if printEntryBlockArgs is set and there are arguments to
3708  // print.
3709  bool shouldAlwaysPrintBlockHeader =
3710  (printEmptyBlock && entryBlock->empty()) ||
3711  (printEntryBlockArgs && entryBlock->getNumArguments() != 0);
3712  print(entryBlock, shouldAlwaysPrintBlockHeader, printBlockTerminators);
3713  for (auto &b : llvm::drop_begin(region.getBlocks(), 1))
3714  print(&b);
3715  }
3716  os.indent(currentIndent) << "}";
3717 }
3718 
3719 void OperationPrinter::printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3720  ValueRange operands) {
3721  if (!mapAttr) {
3722  os << "<<NULL AFFINE MAP>>";
3723  return;
3724  }
3725  AffineMap map = mapAttr.getValue();
3726  unsigned numDims = map.getNumDims();
3727  auto printValueName = [&](unsigned pos, bool isSymbol) {
3728  unsigned index = isSymbol ? numDims + pos : pos;
3729  assert(index < operands.size());
3730  if (isSymbol)
3731  os << "symbol(";
3732  printValueID(operands[index]);
3733  if (isSymbol)
3734  os << ')';
3735  };
3736 
3737  interleaveComma(map.getResults(), [&](AffineExpr expr) {
3738  printAffineExpr(expr, printValueName);
3739  });
3740 }
3741 
3742 void OperationPrinter::printAffineExprOfSSAIds(AffineExpr expr,
3743  ValueRange dimOperands,
3744  ValueRange symOperands) {
3745  auto printValueName = [&](unsigned pos, bool isSymbol) {
3746  if (!isSymbol)
3747  return printValueID(dimOperands[pos]);
3748  os << "symbol(";
3749  printValueID(symOperands[pos]);
3750  os << ')';
3751  };
3752  printAffineExpr(expr, printValueName);
3753 }
3754 
3755 //===----------------------------------------------------------------------===//
3756 // print and dump methods
3757 //===----------------------------------------------------------------------===//
3758 
3759 void Attribute::print(raw_ostream &os, bool elideType) const {
3760  if (!*this) {
3761  os << "<<NULL ATTRIBUTE>>";
3762  return;
3763  }
3764 
3765  AsmState state(getContext());
3766  print(os, state, elideType);
3767 }
3768 void Attribute::print(raw_ostream &os, AsmState &state, bool elideType) const {
3769  using AttrTypeElision = AsmPrinter::Impl::AttrTypeElision;
3770  AsmPrinter::Impl(os, state.getImpl())
3771  .printAttribute(*this, elideType ? AttrTypeElision::Must
3772  : AttrTypeElision::Never);
3773 }
3774 
3775 void Attribute::dump() const {
3776  print(llvm::errs());
3777  llvm::errs() << "\n";
3778 }
3779 
3780 void Attribute::printStripped(raw_ostream &os, AsmState &state) const {
3781  if (!*this) {
3782  os << "<<NULL ATTRIBUTE>>";
3783  return;
3784  }
3785 
3786  AsmPrinter::Impl subPrinter(os, state.getImpl());
3787  if (succeeded(subPrinter.printAlias(*this)))
3788  return;
3789 
3790  auto &dialect = this->getDialect();
3791  uint64_t posPrior = os.tell();
3792  DialectAsmPrinter printer(subPrinter);
3793  dialect.printAttribute(*this, printer);
3794  if (posPrior != os.tell())
3795  return;
3796 
3797  // Fallback to printing with prefix if the above failed to write anything
3798  // to the output stream.
3799  print(os, state);
3800 }
3801 void Attribute::printStripped(raw_ostream &os) const {
3802  if (!*this) {
3803  os << "<<NULL ATTRIBUTE>>";
3804  return;
3805  }
3806 
3807  AsmState state(getContext());
3808  printStripped(os, state);
3809 }
3810 
3811 void Type::print(raw_ostream &os) const {
3812  if (!*this) {
3813  os << "<<NULL TYPE>>";
3814  return;
3815  }
3816 
3817  AsmState state(getContext());
3818  print(os, state);
3819 }
3820 void Type::print(raw_ostream &os, AsmState &state) const {
3821  AsmPrinter::Impl(os, state.getImpl()).printType(*this);
3822 }
3823 
3824 void Type::dump() const {
3825  print(llvm::errs());
3826  llvm::errs() << "\n";
3827 }
3828 
3829 void AffineMap::dump() const {
3830  print(llvm::errs());
3831  llvm::errs() << "\n";
3832 }
3833 
3834 void IntegerSet::dump() const {
3835  print(llvm::errs());
3836  llvm::errs() << "\n";
3837 }
3838 
3839 void AffineExpr::print(raw_ostream &os) const {
3840  if (!expr) {
3841  os << "<<NULL AFFINE EXPR>>";
3842  return;
3843  }
3844  AsmState state(getContext());
3845  AsmPrinter::Impl(os, state.getImpl()).printAffineExpr(*this);
3846 }
3847 
3848 void AffineExpr::dump() const {
3849  print(llvm::errs());
3850  llvm::errs() << "\n";
3851 }
3852 
3853 void AffineMap::print(raw_ostream &os) const {
3854  if (!map) {
3855  os << "<<NULL AFFINE MAP>>";
3856  return;
3857  }
3858  AsmState state(getContext());
3859  AsmPrinter::Impl(os, state.getImpl()).printAffineMap(*this);
3860 }
3861 
3862 void IntegerSet::print(raw_ostream &os) const {
3863  AsmState state(getContext());
3864  AsmPrinter::Impl(os, state.getImpl()).printIntegerSet(*this);
3865 }
3866 
3867 void Value::print(raw_ostream &os) const { print(os, OpPrintingFlags()); }
3868 void Value::print(raw_ostream &os, const OpPrintingFlags &flags) const {
3869  if (!impl) {
3870  os << "<<NULL VALUE>>";
3871  return;
3872  }
3873 
3874  if (auto *op = getDefiningOp())
3875  return op->print(os, flags);
3876  // TODO: Improve BlockArgument print'ing.
3877  BlockArgument arg = llvm::cast<BlockArgument>(*this);
3878  os << "<block argument> of type '" << arg.getType()
3879  << "' at index: " << arg.getArgNumber();
3880 }
3881 void Value::print(raw_ostream &os, AsmState &state) const {
3882  if (!impl) {
3883  os << "<<NULL VALUE>>";
3884  return;
3885  }
3886 
3887  if (auto *op = getDefiningOp())
3888  return op->print(os, state);
3889 
3890  // TODO: Improve BlockArgument print'ing.
3891  BlockArgument arg = llvm::cast<BlockArgument>(*this);
3892  os << "<block argument> of type '" << arg.getType()
3893  << "' at index: " << arg.getArgNumber();
3894 }
3895 
3896 void Value::dump() const {
3897  print(llvm::errs());
3898  llvm::errs() << "\n";
3899 }
3900 
3901 void Value::printAsOperand(raw_ostream &os, AsmState &state) const {
3902  // TODO: This doesn't necessarily capture all potential cases.
3903  // Currently, region arguments can be shadowed when printing the main
3904  // operation. If the IR hasn't been printed, this will produce the old SSA
3905  // name and not the shadowed name.
3906  state.getImpl().getSSANameState().printValueID(*this, /*printResultNo=*/true,
3907  os);
3908 }
3909 
3910 static Operation *findParent(Operation *op, bool shouldUseLocalScope) {
3911  do {
3912  // If we are printing local scope, stop at the first operation that is
3913  // isolated from above.
3914  if (shouldUseLocalScope && op->hasTrait<OpTrait::IsIsolatedFromAbove>())
3915  break;
3916 
3917  // Otherwise, traverse up to the next parent.
3918  Operation *parentOp = op->getParentOp();
3919  if (!parentOp)
3920  break;
3921  op = parentOp;
3922  } while (true);
3923  return op;
3924 }
3925 
3926 void Value::printAsOperand(raw_ostream &os,
3927  const OpPrintingFlags &flags) const {
3928  Operation *op;
3929  if (auto result = llvm::dyn_cast<OpResult>(*this)) {
3930  op = result.getOwner();
3931  } else {
3932  op = llvm::cast<BlockArgument>(*this).getOwner()->getParentOp();
3933  if (!op) {
3934  os << "<<UNKNOWN SSA VALUE>>";
3935  return;
3936  }
3937  }
3938  op = findParent(op, flags.shouldUseLocalScope());
3939  AsmState state(op, flags);
3940  printAsOperand(os, state);
3941 }
3942 
3943 void Operation::print(raw_ostream &os, const OpPrintingFlags &printerFlags) {
3944  // Find the operation to number from based upon the provided flags.
3945  Operation *op = findParent(this, printerFlags.shouldUseLocalScope());
3946  AsmState state(op, printerFlags);
3947  print(os, state);
3948 }
3949 void Operation::print(raw_ostream &os, AsmState &state) {
3950  OperationPrinter printer(os, state.getImpl());
3951  if (!getParent() && !state.getPrinterFlags().shouldUseLocalScope()) {
3952  state.getImpl().initializeAliases(this);
3953  printer.printTopLevelOperation(this);
3954  } else {
3955  printer.printFullOpWithIndentAndLoc(this);
3956  }
3957 }
3958 
3960  print(llvm::errs(), OpPrintingFlags().useLocalScope());
3961  llvm::errs() << "\n";
3962 }
3963 
3964 void Block::print(raw_ostream &os) {
3965  Operation *parentOp = getParentOp();
3966  if (!parentOp) {
3967  os << "<<UNLINKED BLOCK>>\n";
3968  return;
3969  }
3970  // Get the top-level op.
3971  while (auto *nextOp = parentOp->getParentOp())
3972  parentOp = nextOp;
3973 
3974  AsmState state(parentOp);
3975  print(os, state);
3976 }
3977 void Block::print(raw_ostream &os, AsmState &state) {
3978  OperationPrinter(os, state.getImpl()).print(this);
3979 }
3980 
3981 void Block::dump() { print(llvm::errs()); }
3982 
3983 /// Print out the name of the block without printing its body.
3984 void Block::printAsOperand(raw_ostream &os, bool printType) {
3985  Operation *parentOp = getParentOp();
3986  if (!parentOp) {
3987  os << "<<UNLINKED BLOCK>>\n";
3988  return;
3989  }
3990  AsmState state(parentOp);
3991  printAsOperand(os, state);
3992 }
3993 void Block::printAsOperand(raw_ostream &os, AsmState &state) {
3994  OperationPrinter printer(os, state.getImpl());
3995  printer.printBlockName(this);
3996 }
3997 
3998 raw_ostream &mlir::operator<<(raw_ostream &os, Block &block) {
3999  block.print(os);
4000  return os;
4001 }
4002 
4003 //===--------------------------------------------------------------------===//
4004 // Custom printers
4005 //===--------------------------------------------------------------------===//
4006 namespace mlir {
4007 
4009  ArrayRef<int64_t> dimensions) {
4010  if (dimensions.empty())
4011  printer << "[";
4012  printer.printDimensionList(dimensions);
4013  if (dimensions.empty())
4014  printer << "]";
4015 }
4016 
4017 ParseResult parseDimensionList(OpAsmParser &parser,
4018  DenseI64ArrayAttr &dimensions) {
4019  // Empty list case denoted by "[]".
4020  if (succeeded(parser.parseOptionalLSquare())) {
4021  if (failed(parser.parseRSquare())) {
4022  return parser.emitError(parser.getCurrentLocation())
4023  << "Failed parsing dimension list.";
4024  }
4025  dimensions =
4027  return success();
4028  }
4029 
4030  // Non-empty list case.
4031  SmallVector<int64_t> shapeArr;
4032  if (failed(parser.parseDimensionList(shapeArr, true, false))) {
4033  return parser.emitError(parser.getCurrentLocation())
4034  << "Failed parsing dimension list.";
4035  }
4036  if (shapeArr.empty()) {
4037  return parser.emitError(parser.getCurrentLocation())
4038  << "Failed parsing dimension list. Did you mean an empty list? It "
4039  "must be denoted by \"[]\".";
4040  }
4041  dimensions = DenseI64ArrayAttr::get(parser.getContext(), shapeArr);
4042  return success();
4043 }
4044 
4045 } // namespace mlir
static StringRef sanitizeIdentifier(StringRef name, SmallString< 16 > &buffer, StringRef allowedPunctChars="$._-", bool allowTrailingDigit=true)
Sanitize the given name such that it can be used as a valid identifier.
Definition: AsmPrinter.cpp:998
static void printSymbolReference(StringRef symbolRef, raw_ostream &os)
Print the given string as a symbol reference.
static void printFloatValue(const APFloat &apValue, raw_ostream &os, bool *printedHex=nullptr)
Print a floating point value in a way that the parser will be able to round-trip losslessly.
static llvm::ManagedStatic< AsmPrinterOptions > clOptions
Definition: AsmPrinter.cpp:201
static Operation * findParent(Operation *op, bool shouldUseLocalScope)
static void printKeywordOrString(StringRef keyword, raw_ostream &os)
Print the given string as a keyword, or a quoted and escaped string if it has any special or non-prin...
static bool isDialectSymbolSimpleEnoughForPrettyForm(StringRef symName)
Returns true if the given dialect symbol data is simple enough to print in the pretty form.
static void printDialectSymbol(raw_ostream &os, StringRef symPrefix, StringRef dialectName, StringRef symString)
Print the given dialect symbol to the stream.
#define DEBUG_TYPE
Definition: AsmPrinter.cpp:59
static OpPrintingFlags verifyOpAndAdjustFlags(Operation *op, OpPrintingFlags printerFlags)
Verifies the operation and switches to generic op printing if verification fails.
MLIR_CRUNNERUTILS_EXPORT void printString(char const *s)
MLIR_CRUNNERUTILS_EXPORT void printNewline()
static void visit(Operation *op, DenseSet< Operation * > &visited)
Visits all the pdl.operand(s), pdl.result(s), and pdl.operation(s) connected to the given operation.
Definition: PDL.cpp:63
static MLIRContext * getContext(OpFoldResult val)
static std::string diag(const llvm::Value &value)
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
static void printRegion(llvm::raw_ostream &os, Region *region, OpPrintingFlags &flags)
Definition: Unit.cpp:28
Base type for affine expression.
Definition: AffineExpr.h:68
AffineExprKind getKind() const
Return the classification for this type.
Definition: AffineExpr.cpp:35
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
Definition: AffineMap.h:46
unsigned getNumSymbols() const
Definition: AffineMap.cpp:398
unsigned getNumDims() const
Definition: AffineMap.cpp:394
ArrayRef< AffineExpr > getResults() const
Definition: AffineMap.cpp:407
This class represents an opaque handle to a dialect resource entry.
Dialect * getDialect() const
Return the dialect that owns the resource.
This class represents a single parsed resource entry.
Definition: AsmState.h:283
virtual FailureOr< AsmResourceBlob > parseAsBlob(BlobAllocatorFn allocator) const =0
Parse the resource entry represented by a binary blob.
virtual InFlightDiagnostic emitError() const =0
Emit an error at the location of this entry.
virtual AsmResourceEntryKind getKind() const =0
Return the kind of this value.
virtual FailureOr< std::string > parseAsString() const =0
Parse the resource entry represented by a human-readable string.
virtual FailureOr< bool > parseAsBool() const =0
Parse the resource entry represented by a boolean.
virtual StringRef getKey() const =0
Return the key of the resource entry.
MLIRContext * getContext() const
Definition: AsmPrinter.cpp:73
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
virtual ParseResult parseRSquare()=0
Parse a ] token.
virtual ParseResult parseDimensionList(SmallVectorImpl< int64_t > &dimensions, bool allowDynamic=true, bool withTrailingX=true)=0
Parse a dimension list of a tensor or memref type.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
virtual ~AsmParser()
ParseResult parseTypeList(SmallVectorImpl< Type > &result)
Parse a type list.
Definition: AsmPrinter.cpp:77
virtual ParseResult parseOptionalLSquare()=0
Parse a [ token if present.
Impl(raw_ostream &os, AsmStateImpl &state)
BindingStrength
This enum is used to represent the binding strength of the enclosing context that an AffineExprStorag...
Definition: AsmPrinter.cpp:491
void printHexString(StringRef str)
Print a hex string, wrapped with "".
void printDenseArrayAttr(DenseArrayAttr attr)
Print a dense array attribute.
void printDenseElementsAttr(DenseElementsAttr attr, bool allowHex)
Print a dense elements attribute.
void printAttribute(Attribute attr, AttrTypeElision typeElision=AttrTypeElision::Never)
Print the given attribute or an alias.
void printDimensionList(ArrayRef< int64_t > shape)
OpPrintingFlags printerFlags
A set of flags to control the printer's behavior.
Definition: AsmPrinter.cpp:506
raw_ostream & os
The output stream for the printer.
Definition: AsmPrinter.cpp:500
void printResourceHandle(const AsmDialectResourceHandle &resource)
Print a reference to the given resource that is owned by the given dialect.
raw_ostream & getStream()
Returns the output stream of the printer.
Definition: AsmPrinter.cpp:394
LogicalResult printAlias(Attribute attr)
Print the alias for the given attribute, return failure if no alias could be printed.
void printDialectAttribute(Attribute attr)
void interleaveComma(const Container &c, UnaryFunctor eachFn) const
Definition: AsmPrinter.cpp:397
void printDialectType(Type type)
void printLocation(LocationAttr loc, bool allowAlias=false)
Print the given location to the stream.
AsmStateImpl & state
An underlying assembly printer state.
Definition: AsmPrinter.cpp:503
void printAffineMap(AffineMap map)
void printTrailingLocation(Location loc, bool allowAlias=true)
void printAffineExprInternal(AffineExpr expr, BindingStrength enclosingTightness, function_ref< void(unsigned, bool)> printValueName=nullptr)
void printEscapedString(StringRef str)
Print an escaped string, wrapped with "".
void printAffineExpr(AffineExpr expr, function_ref< void(unsigned, bool)> printValueName=nullptr)
void printDenseStringElementsAttr(DenseStringElementsAttr attr)
Print a dense string elements attribute.
void printAttributeImpl(Attribute attr, AttrTypeElision typeElision=AttrTypeElision::Never)
Print the given attribute without considering an alias.
void printAffineConstraint(AffineExpr expr, bool isEq)
void printDenseIntOrFPElementsAttr(DenseIntOrFPElementsAttr attr, bool allowHex)
Print a dense elements attribute.
AttrTypeElision
This enum describes the different kinds of elision for the type of an attribute when printing it.
Definition: AsmPrinter.cpp:403
@ May
The type may be elided when it matches the default used in the parser (for example i64 is the default...
@ Never
The type must not be elided,.
@ Must
The type must be elided.
LogicalResult pushCyclicPrinting(const void *opaquePointer)
void printIntegerSet(IntegerSet set)
NewLineCounter newLine
A tracker for the number of new lines emitted during printing.
Definition: AsmPrinter.cpp:509
void printOptionalAttrDict(ArrayRef< NamedAttribute > attrs, ArrayRef< StringRef > elidedAttrs={}, bool withKeyword=false)
void printType(Type type)
Print the given type or an alias.
void printLocationInternal(LocationAttr loc, bool pretty=false, bool isTopLevel=false)
void printTypeImpl(Type type)
Print the given type.
void printNamedAttribute(NamedAttribute attr)
virtual void printAttributeWithoutType(Attribute attr)
Print the given attribute without its type.
virtual LogicalResult printAlias(Attribute attr)
Print the alias for the given attribute, return failure if no alias could be printed.
virtual void popCyclicPrinting()
Removes the element that was last inserted with a successful call to pushCyclicPrinting.
virtual LogicalResult pushCyclicPrinting(const void *opaquePointer)
Pushes a new attribute or type in the form of a type erased pointer into an internal set.
virtual void printType(Type type)
virtual void printKeywordOrString(StringRef keyword)
Print the given string as a keyword, or a quoted and escaped string if it has any special or non-prin...
virtual void printSymbolName(StringRef symbolRef)
Print the given string as a symbol reference, i.e.
virtual void printString(StringRef string)
Print the given string as a quoted string, escaping any special or non-printable characters in it.
virtual void printAttribute(Attribute attr)
void printDimensionList(ArrayRef< int64_t > shape)
virtual ~AsmPrinter()
virtual raw_ostream & getStream() const
Return the raw output stream used by this printer.
virtual void printResourceHandle(const AsmDialectResourceHandle &resource)
Print a handle to the given dialect resource.
virtual void printFloat(const APFloat &value)
Print the given floating point value in a stabilized form that can be roundtripped through the IR.
This class is used to build resource entries for use by the printer.
Definition: AsmState.h:239
virtual void buildString(StringRef key, StringRef data)=0
Build a resource entry represented by the given human-readable string value.
virtual void buildBool(StringRef key, bool data)=0
Build a resource entry represented by the given bool.
virtual void buildBlob(StringRef key, ArrayRef< char > data, uint32_t dataAlignment)=0
Build an resource entry represented by the given binary blob data.
This class represents an instance of a resource parser.
Definition: AsmState.h:330
static std::unique_ptr< AsmResourcePrinter > fromCallable(StringRef name, CallableT &&printFn)
Return a resource printer implemented via the given callable, whose form should match that of buildRe...
Definition: AsmState.h:391
This class provides management for the lifetime of the state used when printing the IR.
Definition: AsmState.h:533
void attachResourcePrinter(std::unique_ptr< AsmResourcePrinter > printer)
Attach the given resource printer to the AsmState.
DenseMap< Dialect *, SetVector< AsmDialectResourceHandle > > & getDialectResources() const
Returns a map of dialect resources that were referenced when using this state to print IR.
void attachFallbackResourcePrinter(FallbackAsmResourceMap &map)
Attach resource printers to the AsmState for the fallback resources in the given map.
Definition: AsmState.h:579
const OpPrintingFlags & getPrinterFlags() const
Get the printer flags.
Attributes are known-constant values of operations.
Definition: Attributes.h:25
Dialect & getDialect() const
Get the dialect this attribute is registered to.
Definition: Attributes.h:76
bool hasTrait()
Returns true if the type was registered with a particular trait.
Definition: Attributes.h:110
const void * getAsOpaquePointer() const
Get an opaque pointer to the attribute.
Definition: Attributes.h:91
static Attribute getFromOpaquePointer(const void *ptr)
Construct an attribute from the opaque pointer representation.
Definition: Attributes.h:93
This class represents an argument of a Block.
Definition: Value.h:319
Location getLoc() const
Return the location for this argument.
Definition: Value.h:334
unsigned getArgNumber() const
Returns the number of this argument.
Definition: Value.h:331
Block represents an ordered list of Operations.
Definition: Block.h:31
bool empty()
Definition: Block.h:146
Operation & back()
Definition: Block.h:150
void printAsOperand(raw_ostream &os, bool printType=true)
Print out the name of the block without printing its body.
void print(raw_ostream &os)
BlockArgListType getArguments()
Definition: Block.h:85
iterator end()
Definition: Block.h:142
iterator begin()
Definition: Block.h:141
bool isEntryBlock()
Return if this block is the entry block in the parent region.
Definition: Block.cpp:35
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
Definition: Block.cpp:30
An attribute that represents a reference to a dense vector or tensor object.
This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine.
Definition: Diagnostics.h:155
~DialectAsmParser() override
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
~DialectAsmPrinter() override
A collection of dialect interfaces within a context, for a given concrete interface type.
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
Definition: Dialect.h:38
virtual void printAttribute(Attribute, DialectAsmPrinter &) const
Print an attribute registered to this dialect.
Definition: Dialect.h:99
virtual void printType(Type, DialectAsmPrinter &) const
Print a type registered to this dialect.
Definition: Dialect.h:107
An attribute that associates a referenced attribute with a unique identifier.
A fallback map containing external resources not explicitly handled by another parser/printer.
Definition: AsmState.h:412
std::vector< std::unique_ptr< AsmResourcePrinter > > getPrinters()
Build a set of resource printers to print the resources within this map.
An integer set representing a conjunction of one or more affine equalities and inequalities.
Definition: IntegerSet.h:44
unsigned getNumDims() const
Definition: IntegerSet.cpp:15
unsigned getNumConstraints() const
Definition: IntegerSet.cpp:21
AffineExpr getConstraint(unsigned idx) const
Definition: IntegerSet.cpp:45
bool isEq(unsigned idx) const
Returns true if the idx^th constraint is an equality, false if it is an inequality.
Definition: IntegerSet.cpp:55
unsigned getNumSymbols() const
Definition: IntegerSet.cpp:16
Location objects represent source locations information in MLIR.
Definition: Location.h:31
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:63
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:60
NamedAttribute represents a combination of a name and an Attribute value.
Definition: Attributes.h:207
Attribute getValue() const
Return the value of the attribute.
Definition: Attributes.h:221
virtual std::string getResourceKey(const AsmDialectResourceHandle &handle) const
Return a key to use for the given resource.
virtual LogicalResult parseResource(AsmParsedResourceEntry &entry) const
Hook for parsing resource entries.
Definition: AsmPrinter.cpp:130
AliasResult
Holds the result of getAlias hook call.
@ FinalAlias
An alias was provided and it should be used (no other hooks will be checked).
@ NoAlias
The object (type or attribute) is not supported by the hook and an alias was not provided.
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
~OpAsmParser() override
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
void printFunctionalType(Operation *op)
Print the complete type of an operation in functional form.
Definition: AsmPrinter.cpp:94
~OpAsmPrinter() override
Set of flags used to control the behavior of the various IR print methods (e.g.
bool shouldElideElementsAttr(ElementsAttr attr) const
Return if the given ElementsAttr should be elided.
Definition: AsmPrinter.cpp:300
std::optional< int64_t > getLargeElementsAttrLimit() const
Return the size limit for printing large ElementsAttr.
Definition: AsmPrinter.cpp:315
bool shouldAssumeVerified() const
Return if operation verification should be skipped.
Definition: AsmPrinter.cpp:348
OpPrintingFlags & printValueUsers()
Print users of values as comments.
Definition: AsmPrinter.cpp:294
OpPrintingFlags & printLargeElementsAttrWithHex(int64_t largeElementLimit=100)
Enables the printing of large element attributes with a hex string.
Definition: AsmPrinter.cpp:247
bool shouldUseLocalScope() const
Return if the printer should use local scope when dumping the IR.
Definition: AsmPrinter.cpp:353
bool shouldPrintDebugInfoPrettyForm() const
Return if debug information should be printed in the pretty form.
Definition: AsmPrinter.cpp:335
bool shouldPrintElementsAttrWithHex(ElementsAttr attr) const
Return if the given ElementsAttr should be printed as hex string.
Definition: AsmPrinter.cpp:307
bool shouldPrintUniqueSSAIDs() const
Return if printer should use unique SSA IDs.
Definition: AsmPrinter.cpp:361
bool shouldPrintValueUsers() const
Return if the printer should print users of values.
Definition: AsmPrinter.cpp:356
int64_t getLargeElementsAttrHexLimit() const
Return the size limit for printing large ElementsAttr as hex string.
Definition: AsmPrinter.cpp:320
bool shouldPrintGenericOpForm() const
Return if operations should be printed in the generic form.
Definition: AsmPrinter.cpp:340
OpPrintingFlags & elideLargeResourceString(int64_t largeResourceLimit=64)
Enables the elision of large resources strings by omitting them from the dialect_resources section.
Definition: AsmPrinter.cpp:253
bool shouldPrintDebugInfo() const
Return if debug information should be printed.
Definition: AsmPrinter.cpp:330
OpPrintingFlags & elideLargeElementsAttrs(int64_t largeElementLimit=16)
Enables the elision of large elements attributes by printing a lexically valid but otherwise meaningl...
Definition: AsmPrinter.cpp:241
OpPrintingFlags & enableDebugInfo(bool enable=true, bool prettyForm=false)
Enable or disable printing of debug information (based on enable).
Definition: AsmPrinter.cpp:260
OpPrintingFlags()
Initialize the printing flags with default supplied by the cl::opts above.
Definition: AsmPrinter.cpp:211
bool shouldSkipRegions() const
Return if regions should be skipped.
Definition: AsmPrinter.cpp:345
OpPrintingFlags & printGenericOpForm(bool enable=true)
Always print operations in the generic form.
Definition: AsmPrinter.cpp:268
OpPrintingFlags & assumeVerified()
Do not verify the operation when using custom operation printers.
Definition: AsmPrinter.cpp:280
std::optional< uint64_t > getLargeResourceStringLimit() const
Return the size limit in chars for printing large resources.
Definition: AsmPrinter.cpp:325
OpPrintingFlags & useLocalScope()
Use local scope when printing the operation.
Definition: AsmPrinter.cpp:288
OpPrintingFlags & skipRegions(bool skip=true)
Skip printing regions.
Definition: AsmPrinter.cpp:274
This is a value defined by a result of an operation.
Definition: Value.h:457
Operation * getOwner() const
Returns the operation that owns this result.
Definition: Value.h:466
unsigned getResultNumber() const
Returns the number of this result.
Definition: Value.h:469
This class provides the API for ops that are known to be isolated from above.
This class provides the API for ops that are known to be terminators.
Definition: OpDefinition.h:764
void dump() const
Definition: AsmPrinter.cpp:63
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
void printAssembly(Operation *op, OpAsmPrinter &p, StringRef defaultDialect) const
This hook implements the AsmPrinter for this operation.
void print(raw_ostream &os) const
Definition: AsmPrinter.cpp:61
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
bool use_empty()
Returns true if this operation has no uses.
Definition: Operation.h:848
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
Definition: Operation.h:745
Dialect * getDialect()
Return the dialect this operation is associated with, or nullptr if the associated dialect is not loa...
Definition: Operation.h:220
unsigned getNumSuccessors()
Definition: Operation.h:702
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Definition: Operation.h:402
void print(raw_ostream &os, const OpPrintingFlags &flags=std::nullopt)
MLIRContext * getContext()
Return the context this operation is associated with.
Definition: Operation.h:216
std::optional< RegisteredOperationName > getRegisteredInfo()
If this operation has a registered operation description, return it.
Definition: Operation.h:123
Location getLoc()
The source location the operation was defined or derived from.
Definition: Operation.h:223
unsigned getNumOperands()
Definition: Operation.h:341
Attribute getPropertiesAsAttribute()
Return the properties converted to an attribute.
Definition: Operation.cpp:349
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Definition: Operation.h:234
ArrayRef< NamedAttribute > getAttrs()
Return all of the attributes on this operation.
Definition: Operation.h:507
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
Definition: Operation.h:672
OperationName getName()
The name of an operation is the key identifier for it.
Definition: Operation.h:119
operand_type_range getOperandTypes()
Definition: Operation.h:392
result_type_range getResultTypes()
Definition: Operation.h:423
operand_range getOperands()
Returns an iterator on the underlying Value's.
Definition: Operation.h:373
user_range getUsers()
Returns a range of all users.
Definition: Operation.h:869
SuccessorRange getSuccessors()
Definition: Operation.h:699
result_range getResults()
Definition: Operation.h:410
unsigned getNumResults()
Return the number of results held by this operation.
Definition: Operation.h:399
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition: Region.h:26
iterator_range< OpIterator > getOps()
Definition: Region.h:172
Operation * getParentOp()
Return the parent operation this region is attached to.
Definition: Region.h:200
bool empty()
Definition: Region.h:60
unsigned getNumArguments()
Definition: Region.h:123
BlockArgument getArgument(unsigned i)
Definition: Region.h:124
Block & front()
Definition: Region.h:65
This diagnostic handler is a simple RAII class that registers and erases a diagnostic handler on a gi...
Definition: Diagnostics.h:521
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
const void * getAsOpaquePointer() const
Methods for supporting PointerLikeTypeTraits.
Definition: Types.h:183
Dialect & getDialect() const
Get the dialect this type is registered to.
Definition: Types.h:123
static Type getFromOpaquePointer(const void *pointer)
Definition: Types.h:186
bool hasTrait()
Returns true if the type was registered with a particular trait.
Definition: Types.h:201
void walkImmediateSubElements(function_ref< void(Attribute)> walkAttrsFn, function_ref< void(Type)> walkTypesFn) const
Walk all of the immediately nested sub-attributes and sub-types.
Definition: Types.h:213
This class provides an abstraction over the different types of ranges over Values.
Definition: ValueRange.h:381
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
bool use_empty() const
Returns true if this value has no uses.
Definition: Value.h:218
void dump() const
void print(raw_ostream &os) const
Type getType() const
Return the type of this value.
Definition: Value.h:129
void printAsOperand(raw_ostream &os, AsmState &state) const
Print this value as if it were an operand.
user_range getUsers() const
Definition: Value.h:228
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Definition: Value.cpp:20
void registerOperationLocation(Operation *op, unsigned line, unsigned col)
Register the location, line and column, within the buffer that the given operation was printed at.
const OpPrintingFlags & getPrinterFlags() const
Get the printer flags.
auto getResourcePrinters()
Return the non-dialect resource printers.
LogicalResult pushCyclicPrinting(const void *opaquePointer)
SSANameState & getSSANameState()
Get the state used for SSA names.
DialectInterfaceCollection< OpAsmDialectInterface > & getDialectInterfaces()
Return the dialects within the context that implement OpAsmDialectInterface.
AliasState & getAliasState()
Get the state used for aliases.
void initializeAliases(Operation *op)
Initialize the alias state to enable the printing of aliases.
AsmStateImpl(Operation *op, const OpPrintingFlags &printerFlags, AsmState::LocationMap *locationMap)
DenseMap< Dialect *, SetVector< AsmDialectResourceHandle > > & getDialectResources()
Return the referenced dialect resources within the printer.
AsmStateImpl(MLIRContext *ctx, const OpPrintingFlags &printerFlags, AsmState::LocationMap *locationMap)
DistinctState & getDistinctState()
Get the state used for distinct attribute identifiers.
Base class for DenseArrayAttr that is instantiated and specialized for each supported element type be...
static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef< T > content)
Builder from ArrayRef<T>.
void printType(Type type, AsmPrinter &printer)
Prints an LLVM Dialect type.
LogicalResult parseCommaSeparatedList(llvm::cl::Option &opt, StringRef argName, StringRef optionStr, function_ref< LogicalResult(StringRef)> elementParseFn)
Parse a string containing a list of comma-delimited elements, invoking the given parser for each sub-...
AttrTypeReplacer.
void printDimensionList(raw_ostream &stream, Range &&shape)
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Definition: Matchers.h:285
bool operator<(const Fraction &x, const Fraction &y)
Definition: Fraction.h:82
Include the generated interface declarations.
ParseResult parseDimensionList(OpAsmParser &parser, DenseI64ArrayAttr &dimensions)
StringRef toString(AsmResourceEntryKind kind)
@ CeilDiv
RHS of ceildiv is always a constant or a symbolic expression.
@ Mul
RHS of mul is always a constant or a symbolic expression.
@ Mod
RHS of mod is always a constant or a symbolic expression with a positive value.
@ DimId
Dimensional identifier.
@ FloorDiv
RHS of floordiv is always a constant or a symbolic expression.
@ Constant
Constant integer.
@ SymbolId
Symbolic identifier.
void registerAsmPrinterCLOptions()
Register a set of useful command-line options that can be used to configure various flags within the ...
Definition: AsmPrinter.cpp:205
Type parseType(llvm::StringRef typeStr, MLIRContext *context, size_t *numRead=nullptr, bool isKnownNullTerminated=false)
This parses a single MLIR type to an MLIR context if it was valid.
AsmResourceEntryKind
This enum represents the different kinds of resource values.
Definition: AsmState.h:272
@ String
A string value.
@ Bool
A boolean value.
@ Blob
A blob of data with an accompanying alignment.
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
Definition: Verifier.cpp:421
raw_ostream & operator<<(raw_ostream &os, const AliasResult &result)
Definition: AliasAnalysis.h:78
Represents a range (offset, size, and stride) where each element of the triple may be dynamic or stat...
This trait is used to determine if a storage user, like Type, is mutable or not.