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