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