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