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/BuiltinTypes.h"
20 #include "mlir/IR/Dialect.h"
21 #include "mlir/IR/DialectImplementation.h"
22 #include "mlir/IR/IntegerSet.h"
23 #include "mlir/IR/MLIRContext.h"
24 #include "mlir/IR/OpImplementation.h"
25 #include "mlir/IR/Operation.h"
26 #include "mlir/IR/SubElementInterfaces.h"
27 #include "llvm/ADT/APFloat.h"
28 #include "llvm/ADT/DenseMap.h"
29 #include "llvm/ADT/MapVector.h"
30 #include "llvm/ADT/STLExtras.h"
31 #include "llvm/ADT/ScopeExit.h"
32 #include "llvm/ADT/ScopedHashTable.h"
33 #include "llvm/ADT/SetVector.h"
34 #include "llvm/ADT/SmallString.h"
35 #include "llvm/ADT/StringExtras.h"
36 #include "llvm/ADT/StringSet.h"
37 #include "llvm/ADT/TypeSwitch.h"
38 #include "llvm/Support/CommandLine.h"
39 #include "llvm/Support/Endian.h"
40 #include "llvm/Support/Regex.h"
41 #include "llvm/Support/SaveAndRestore.h"
42 
43 #include <tuple>
44 
45 using namespace mlir;
46 using namespace mlir::detail;
47 
48 void Identifier::print(raw_ostream &os) const { os << str(); }
49 
50 void Identifier::dump() const { print(llvm::errs()); }
51 
52 void OperationName::print(raw_ostream &os) const { os << getStringRef(); }
53 
54 void OperationName::dump() const { print(llvm::errs()); }
55 
56 //===--------------------------------------------------------------------===//
57 // AsmParser
58 //===--------------------------------------------------------------------===//
59 
60 AsmParser::~AsmParser() {}
61 DialectAsmParser::~DialectAsmParser() {}
62 OpAsmParser::~OpAsmParser() {}
63 
64 MLIRContext *AsmParser::getContext() const { return getBuilder().getContext(); }
65 
66 //===----------------------------------------------------------------------===//
67 // DialectAsmPrinter
68 //===----------------------------------------------------------------------===//
69 
70 DialectAsmPrinter::~DialectAsmPrinter() {}
71 
72 //===----------------------------------------------------------------------===//
73 // OpAsmPrinter
74 //===----------------------------------------------------------------------===//
75 
76 OpAsmPrinter::~OpAsmPrinter() {}
77 
78 void OpAsmPrinter::printFunctionalType(Operation *op) {
79   auto &os = getStream();
80   os << '(';
81   llvm::interleaveComma(op->getOperands(), os, [&](Value operand) {
82     // Print the types of null values as <<NULL TYPE>>.
83     *this << (operand ? operand.getType() : Type());
84   });
85   os << ") -> ";
86 
87   // Print the result list.  We don't parenthesize single result types unless
88   // it is a function (avoiding a grammar ambiguity).
89   bool wrapped = op->getNumResults() != 1;
90   if (!wrapped && op->getResult(0).getType() &&
91       op->getResult(0).getType().isa<FunctionType>())
92     wrapped = true;
93 
94   if (wrapped)
95     os << '(';
96 
97   llvm::interleaveComma(op->getResults(), os, [&](const OpResult &result) {
98     // Print the types of null values as <<NULL TYPE>>.
99     *this << (result ? result.getType() : Type());
100   });
101 
102   if (wrapped)
103     os << ')';
104 }
105 
106 //===----------------------------------------------------------------------===//
107 // Operation OpAsm interface.
108 //===----------------------------------------------------------------------===//
109 
110 /// The OpAsmOpInterface, see OpAsmInterface.td for more details.
111 #include "mlir/IR/OpAsmInterface.cpp.inc"
112 
113 //===----------------------------------------------------------------------===//
114 // OpPrintingFlags
115 //===----------------------------------------------------------------------===//
116 
117 namespace {
118 /// This struct contains command line options that can be used to initialize
119 /// various bits of the AsmPrinter. This uses a struct wrapper to avoid the need
120 /// for global command line options.
121 struct AsmPrinterOptions {
122   llvm::cl::opt<int64_t> printElementsAttrWithHexIfLarger{
123       "mlir-print-elementsattrs-with-hex-if-larger",
124       llvm::cl::desc(
125           "Print DenseElementsAttrs with a hex string that have "
126           "more elements than the given upper limit (use -1 to disable)")};
127 
128   llvm::cl::opt<unsigned> elideElementsAttrIfLarger{
129       "mlir-elide-elementsattrs-if-larger",
130       llvm::cl::desc("Elide ElementsAttrs with \"...\" that have "
131                      "more elements than the given upper limit")};
132 
133   llvm::cl::opt<bool> printDebugInfoOpt{
134       "mlir-print-debuginfo", llvm::cl::init(false),
135       llvm::cl::desc("Print debug info in MLIR output")};
136 
137   llvm::cl::opt<bool> printPrettyDebugInfoOpt{
138       "mlir-pretty-debuginfo", llvm::cl::init(false),
139       llvm::cl::desc("Print pretty debug info in MLIR output")};
140 
141   // Use the generic op output form in the operation printer even if the custom
142   // form is defined.
143   llvm::cl::opt<bool> printGenericOpFormOpt{
144       "mlir-print-op-generic", llvm::cl::init(false),
145       llvm::cl::desc("Print the generic op form"), llvm::cl::Hidden};
146 
147   llvm::cl::opt<bool> printLocalScopeOpt{
148       "mlir-print-local-scope", llvm::cl::init(false),
149       llvm::cl::desc("Print assuming in local scope by default"),
150       llvm::cl::Hidden};
151 };
152 } // end anonymous namespace
153 
154 static llvm::ManagedStatic<AsmPrinterOptions> clOptions;
155 
156 /// Register a set of useful command-line options that can be used to configure
157 /// various flags within the AsmPrinter.
158 void mlir::registerAsmPrinterCLOptions() {
159   // Make sure that the options struct has been initialized.
160   *clOptions;
161 }
162 
163 /// Initialize the printing flags with default supplied by the cl::opts above.
164 OpPrintingFlags::OpPrintingFlags()
165     : printDebugInfoFlag(false), printDebugInfoPrettyFormFlag(false),
166       printGenericOpFormFlag(false), printLocalScope(false) {
167   // Initialize based upon command line options, if they are available.
168   if (!clOptions.isConstructed())
169     return;
170   if (clOptions->elideElementsAttrIfLarger.getNumOccurrences())
171     elementsAttrElementLimit = clOptions->elideElementsAttrIfLarger;
172   printDebugInfoFlag = clOptions->printDebugInfoOpt;
173   printDebugInfoPrettyFormFlag = clOptions->printPrettyDebugInfoOpt;
174   printGenericOpFormFlag = clOptions->printGenericOpFormOpt;
175   printLocalScope = clOptions->printLocalScopeOpt;
176 }
177 
178 /// Enable the elision of large elements attributes, by printing a '...'
179 /// instead of the element data, when the number of elements is greater than
180 /// `largeElementLimit`. Note: The IR generated with this option is not
181 /// parsable.
182 OpPrintingFlags &
183 OpPrintingFlags::elideLargeElementsAttrs(int64_t largeElementLimit) {
184   elementsAttrElementLimit = largeElementLimit;
185   return *this;
186 }
187 
188 /// Enable printing of debug information. If 'prettyForm' is set to true,
189 /// debug information is printed in a more readable 'pretty' form.
190 OpPrintingFlags &OpPrintingFlags::enableDebugInfo(bool prettyForm) {
191   printDebugInfoFlag = true;
192   printDebugInfoPrettyFormFlag = prettyForm;
193   return *this;
194 }
195 
196 /// Always print operations in the generic form.
197 OpPrintingFlags &OpPrintingFlags::printGenericOpForm() {
198   printGenericOpFormFlag = true;
199   return *this;
200 }
201 
202 /// Use local scope when printing the operation. This allows for using the
203 /// printer in a more localized and thread-safe setting, but may not necessarily
204 /// be identical of what the IR will look like when dumping the full module.
205 OpPrintingFlags &OpPrintingFlags::useLocalScope() {
206   printLocalScope = true;
207   return *this;
208 }
209 
210 /// Return if the given ElementsAttr should be elided.
211 bool OpPrintingFlags::shouldElideElementsAttr(ElementsAttr attr) const {
212   return elementsAttrElementLimit.hasValue() &&
213          *elementsAttrElementLimit < int64_t(attr.getNumElements()) &&
214          !attr.isa<SplatElementsAttr>();
215 }
216 
217 /// Return the size limit for printing large ElementsAttr.
218 Optional<int64_t> OpPrintingFlags::getLargeElementsAttrLimit() const {
219   return elementsAttrElementLimit;
220 }
221 
222 /// Return if debug information should be printed.
223 bool OpPrintingFlags::shouldPrintDebugInfo() const {
224   return printDebugInfoFlag;
225 }
226 
227 /// Return if debug information should be printed in the pretty form.
228 bool OpPrintingFlags::shouldPrintDebugInfoPrettyForm() const {
229   return printDebugInfoPrettyFormFlag;
230 }
231 
232 /// Return if operations should be printed in the generic form.
233 bool OpPrintingFlags::shouldPrintGenericOpForm() const {
234   return printGenericOpFormFlag;
235 }
236 
237 /// Return if the printer should use local scope when dumping the IR.
238 bool OpPrintingFlags::shouldUseLocalScope() const { return printLocalScope; }
239 
240 /// Returns true if an ElementsAttr with the given number of elements should be
241 /// printed with hex.
242 static bool shouldPrintElementsAttrWithHex(int64_t numElements) {
243   // Check to see if a command line option was provided for the limit.
244   if (clOptions.isConstructed()) {
245     if (clOptions->printElementsAttrWithHexIfLarger.getNumOccurrences()) {
246       // -1 is used to disable hex printing.
247       if (clOptions->printElementsAttrWithHexIfLarger == -1)
248         return false;
249       return numElements > clOptions->printElementsAttrWithHexIfLarger;
250     }
251   }
252 
253   // Otherwise, default to printing with hex if the number of elements is >100.
254   return numElements > 100;
255 }
256 
257 //===----------------------------------------------------------------------===//
258 // NewLineCounter
259 //===----------------------------------------------------------------------===//
260 
261 namespace {
262 /// This class is a simple formatter that emits a new line when inputted into a
263 /// stream, that enables counting the number of newlines emitted. This class
264 /// should be used whenever emitting newlines in the printer.
265 struct NewLineCounter {
266   unsigned curLine = 1;
267 };
268 
269 static raw_ostream &operator<<(raw_ostream &os, NewLineCounter &newLine) {
270   ++newLine.curLine;
271   return os << '\n';
272 }
273 } // end anonymous namespace
274 
275 //===----------------------------------------------------------------------===//
276 // AliasInitializer
277 //===----------------------------------------------------------------------===//
278 
279 namespace {
280 /// This class represents a specific instance of a symbol Alias.
281 class SymbolAlias {
282 public:
283   SymbolAlias(StringRef name, bool isDeferrable)
284       : name(name), suffixIndex(0), hasSuffixIndex(false),
285         isDeferrable(isDeferrable) {}
286   SymbolAlias(StringRef name, uint32_t suffixIndex, bool isDeferrable)
287       : name(name), suffixIndex(suffixIndex), hasSuffixIndex(true),
288         isDeferrable(isDeferrable) {}
289 
290   /// Print this alias to the given stream.
291   void print(raw_ostream &os) const {
292     os << name;
293     if (hasSuffixIndex)
294       os << suffixIndex;
295   }
296 
297   /// Returns true if this alias supports deferred resolution when parsing.
298   bool canBeDeferred() const { return isDeferrable; }
299 
300 private:
301   /// The main name of the alias.
302   StringRef name;
303   /// The optional suffix index of the alias, if multiple aliases had the same
304   /// name.
305   uint32_t suffixIndex : 30;
306   /// A flag indicating whether this alias has a suffix or not.
307   bool hasSuffixIndex : 1;
308   /// A flag indicating whether this alias may be deferred or not.
309   bool isDeferrable : 1;
310 };
311 
312 /// This class represents a utility that initializes the set of attribute and
313 /// type aliases, without the need to store the extra information within the
314 /// main AliasState class or pass it around via function arguments.
315 class AliasInitializer {
316 public:
317   AliasInitializer(
318       DialectInterfaceCollection<OpAsmDialectInterface> &interfaces,
319       llvm::BumpPtrAllocator &aliasAllocator)
320       : interfaces(interfaces), aliasAllocator(aliasAllocator),
321         aliasOS(aliasBuffer) {}
322 
323   void initialize(Operation *op, const OpPrintingFlags &printerFlags,
324                   llvm::MapVector<Attribute, SymbolAlias> &attrToAlias,
325                   llvm::MapVector<Type, SymbolAlias> &typeToAlias);
326 
327   /// Visit the given attribute to see if it has an alias. `canBeDeferred` is
328   /// set to true if the originator of this attribute can resolve the alias
329   /// after parsing has completed (e.g. in the case of operation locations).
330   void visit(Attribute attr, bool canBeDeferred = false);
331 
332   /// Visit the given type to see if it has an alias.
333   void visit(Type type);
334 
335 private:
336   /// Try to generate an alias for the provided symbol. If an alias is
337   /// generated, the provided alias mapping and reverse mapping are updated.
338   /// Returns success if an alias was generated, failure otherwise.
339   template <typename T>
340   LogicalResult
341   generateAlias(T symbol,
342                 llvm::MapVector<StringRef, std::vector<T>> &aliasToSymbol);
343 
344   /// The set of asm interfaces within the context.
345   DialectInterfaceCollection<OpAsmDialectInterface> &interfaces;
346 
347   /// Mapping between an alias and the set of symbols mapped to it.
348   llvm::MapVector<StringRef, std::vector<Attribute>> aliasToAttr;
349   llvm::MapVector<StringRef, std::vector<Type>> aliasToType;
350 
351   /// An allocator used for alias names.
352   llvm::BumpPtrAllocator &aliasAllocator;
353 
354   /// The set of visited attributes.
355   DenseSet<Attribute> visitedAttributes;
356 
357   /// The set of attributes that have aliases *and* can be deferred.
358   DenseSet<Attribute> deferrableAttributes;
359 
360   /// The set of visited types.
361   DenseSet<Type> visitedTypes;
362 
363   /// Storage and stream used when generating an alias.
364   SmallString<32> aliasBuffer;
365   llvm::raw_svector_ostream aliasOS;
366 };
367 
368 /// This class implements a dummy OpAsmPrinter that doesn't print any output,
369 /// and merely collects the attributes and types that *would* be printed in a
370 /// normal print invocation so that we can generate proper aliases. This allows
371 /// for us to generate aliases only for the attributes and types that would be
372 /// in the output, and trims down unnecessary output.
373 class DummyAliasOperationPrinter : private OpAsmPrinter {
374 public:
375   explicit DummyAliasOperationPrinter(const OpPrintingFlags &printerFlags,
376                                       AliasInitializer &initializer)
377       : printerFlags(printerFlags), initializer(initializer) {}
378 
379   /// Print the given operation.
380   void print(Operation *op) {
381     // Visit the operation location.
382     if (printerFlags.shouldPrintDebugInfo())
383       initializer.visit(op->getLoc(), /*canBeDeferred=*/true);
384 
385     // If requested, always print the generic form.
386     if (!printerFlags.shouldPrintGenericOpForm()) {
387       // Check to see if this is a known operation.  If so, use the registered
388       // custom printer hook.
389       if (auto *opInfo = op->getAbstractOperation()) {
390         opInfo->printAssembly(op, *this, /*defaultDialect=*/"");
391         return;
392       }
393     }
394 
395     // Otherwise print with the generic assembly form.
396     printGenericOp(op);
397   }
398 
399 private:
400   /// Print the given operation in the generic form.
401   void printGenericOp(Operation *op, bool printOpName = true) override {
402     // Consider nested operations for aliases.
403     if (op->getNumRegions() != 0) {
404       for (Region &region : op->getRegions())
405         printRegion(region, /*printEntryBlockArgs=*/true,
406                     /*printBlockTerminators=*/true);
407     }
408 
409     // Visit all the types used in the operation.
410     for (Type type : op->getOperandTypes())
411       printType(type);
412     for (Type type : op->getResultTypes())
413       printType(type);
414 
415     // Consider the attributes of the operation for aliases.
416     for (const NamedAttribute &attr : op->getAttrs())
417       printAttribute(attr.second);
418   }
419 
420   /// Print the given block. If 'printBlockArgs' is false, the arguments of the
421   /// block are not printed. If 'printBlockTerminator' is false, the terminator
422   /// operation of the block is not printed.
423   void print(Block *block, bool printBlockArgs = true,
424              bool printBlockTerminator = true) {
425     // Consider the types of the block arguments for aliases if 'printBlockArgs'
426     // is set to true.
427     if (printBlockArgs) {
428       for (BlockArgument arg : block->getArguments()) {
429         printType(arg.getType());
430 
431         // Visit the argument location.
432         if (printerFlags.shouldPrintDebugInfo())
433           // TODO: Allow deferring argument locations.
434           initializer.visit(arg.getLoc(), /*canBeDeferred=*/false);
435       }
436     }
437 
438     // Consider the operations within this block, ignoring the terminator if
439     // requested.
440     bool hasTerminator =
441         !block->empty() && block->back().hasTrait<OpTrait::IsTerminator>();
442     auto range = llvm::make_range(
443         block->begin(),
444         std::prev(block->end(),
445                   (!hasTerminator || printBlockTerminator) ? 0 : 1));
446     for (Operation &op : range)
447       print(&op);
448   }
449 
450   /// Print the given region.
451   void printRegion(Region &region, bool printEntryBlockArgs,
452                    bool printBlockTerminators,
453                    bool printEmptyBlock = false) override {
454     if (region.empty())
455       return;
456 
457     auto *entryBlock = &region.front();
458     print(entryBlock, printEntryBlockArgs, printBlockTerminators);
459     for (Block &b : llvm::drop_begin(region, 1))
460       print(&b);
461   }
462 
463   void printRegionArgument(BlockArgument arg, ArrayRef<NamedAttribute> argAttrs,
464                            bool omitType) override {
465     printType(arg.getType());
466     // Visit the argument location.
467     if (printerFlags.shouldPrintDebugInfo())
468       // TODO: Allow deferring argument locations.
469       initializer.visit(arg.getLoc(), /*canBeDeferred=*/false);
470   }
471 
472   /// Consider the given type to be printed for an alias.
473   void printType(Type type) override { initializer.visit(type); }
474 
475   /// Consider the given attribute to be printed for an alias.
476   void printAttribute(Attribute attr) override { initializer.visit(attr); }
477   void printAttributeWithoutType(Attribute attr) override {
478     printAttribute(attr);
479   }
480 
481   /// Print the given set of attributes with names not included within
482   /// 'elidedAttrs'.
483   void printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
484                              ArrayRef<StringRef> elidedAttrs = {}) override {
485     if (attrs.empty())
486       return;
487     if (elidedAttrs.empty()) {
488       for (const NamedAttribute &attr : attrs)
489         printAttribute(attr.second);
490       return;
491     }
492     llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
493                                                   elidedAttrs.end());
494     for (const NamedAttribute &attr : attrs)
495       if (!elidedAttrsSet.contains(attr.first.strref()))
496         printAttribute(attr.second);
497   }
498   void printOptionalAttrDictWithKeyword(
499       ArrayRef<NamedAttribute> attrs,
500       ArrayRef<StringRef> elidedAttrs = {}) override {
501     printOptionalAttrDict(attrs, elidedAttrs);
502   }
503 
504   /// Return a null stream as the output stream, this will ignore any data fed
505   /// to it.
506   raw_ostream &getStream() const override { return os; }
507 
508   /// The following are hooks of `OpAsmPrinter` that are not necessary for
509   /// determining potential aliases.
510   void printFloat(const APFloat &value) override {}
511   void printAffineMapOfSSAIds(AffineMapAttr, ValueRange) override {}
512   void printAffineExprOfSSAIds(AffineExpr, ValueRange, ValueRange) override {}
513   void printNewline() override {}
514   void printOperand(Value) override {}
515   void printOperand(Value, raw_ostream &os) override {
516     // Users expect the output string to have at least the prefixed % to signal
517     // a value name. To maintain this invariant, emit a name even if it is
518     // guaranteed to go unused.
519     os << "%";
520   }
521   void printSymbolName(StringRef) override {}
522   void printSuccessor(Block *) override {}
523   void printSuccessorAndUseList(Block *, ValueRange) override {}
524   void shadowRegionArgs(Region &, ValueRange) override {}
525 
526   /// The printer flags to use when determining potential aliases.
527   const OpPrintingFlags &printerFlags;
528 
529   /// The initializer to use when identifying aliases.
530   AliasInitializer &initializer;
531 
532   /// A dummy output stream.
533   mutable llvm::raw_null_ostream os;
534 };
535 } // end anonymous namespace
536 
537 /// Sanitize the given name such that it can be used as a valid identifier. If
538 /// the string needs to be modified in any way, the provided buffer is used to
539 /// store the new copy,
540 static StringRef sanitizeIdentifier(StringRef name, SmallString<16> &buffer,
541                                     StringRef allowedPunctChars = "$._-",
542                                     bool allowTrailingDigit = true) {
543   assert(!name.empty() && "Shouldn't have an empty name here");
544 
545   auto copyNameToBuffer = [&] {
546     for (char ch : name) {
547       if (llvm::isAlnum(ch) || allowedPunctChars.contains(ch))
548         buffer.push_back(ch);
549       else if (ch == ' ')
550         buffer.push_back('_');
551       else
552         buffer.append(llvm::utohexstr((unsigned char)ch));
553     }
554   };
555 
556   // Check to see if this name is valid. If it starts with a digit, then it
557   // could conflict with the autogenerated numeric ID's, so add an underscore
558   // prefix to avoid problems.
559   if (isdigit(name[0])) {
560     buffer.push_back('_');
561     copyNameToBuffer();
562     return buffer;
563   }
564 
565   // If the name ends with a trailing digit, add a '_' to avoid potential
566   // conflicts with autogenerated ID's.
567   if (!allowTrailingDigit && isdigit(name.back())) {
568     copyNameToBuffer();
569     buffer.push_back('_');
570     return buffer;
571   }
572 
573   // Check to see that the name consists of only valid identifier characters.
574   for (char ch : name) {
575     if (!llvm::isAlnum(ch) && !allowedPunctChars.contains(ch)) {
576       copyNameToBuffer();
577       return buffer;
578     }
579   }
580 
581   // If there are no invalid characters, return the original name.
582   return name;
583 }
584 
585 /// Given a collection of aliases and symbols, initialize a mapping from a
586 /// symbol to a given alias.
587 template <typename T>
588 static void
589 initializeAliases(llvm::MapVector<StringRef, std::vector<T>> &aliasToSymbol,
590                   llvm::MapVector<T, SymbolAlias> &symbolToAlias,
591                   DenseSet<T> *deferrableAliases = nullptr) {
592   std::vector<std::pair<StringRef, std::vector<T>>> aliases =
593       aliasToSymbol.takeVector();
594   llvm::array_pod_sort(aliases.begin(), aliases.end(),
595                        [](const auto *lhs, const auto *rhs) {
596                          return lhs->first.compare(rhs->first);
597                        });
598 
599   for (auto &it : aliases) {
600     // If there is only one instance for this alias, use the name directly.
601     if (it.second.size() == 1) {
602       T symbol = it.second.front();
603       bool isDeferrable = deferrableAliases && deferrableAliases->count(symbol);
604       symbolToAlias.insert({symbol, SymbolAlias(it.first, isDeferrable)});
605       continue;
606     }
607     // Otherwise, add the index to the name.
608     for (int i = 0, e = it.second.size(); i < e; ++i) {
609       T symbol = it.second[i];
610       bool isDeferrable = deferrableAliases && deferrableAliases->count(symbol);
611       symbolToAlias.insert({symbol, SymbolAlias(it.first, i, isDeferrable)});
612     }
613   }
614 }
615 
616 void AliasInitializer::initialize(
617     Operation *op, const OpPrintingFlags &printerFlags,
618     llvm::MapVector<Attribute, SymbolAlias> &attrToAlias,
619     llvm::MapVector<Type, SymbolAlias> &typeToAlias) {
620   // Use a dummy printer when walking the IR so that we can collect the
621   // attributes/types that will actually be used during printing when
622   // considering aliases.
623   DummyAliasOperationPrinter aliasPrinter(printerFlags, *this);
624   aliasPrinter.print(op);
625 
626   // Initialize the aliases sorted by name.
627   initializeAliases(aliasToAttr, attrToAlias, &deferrableAttributes);
628   initializeAliases(aliasToType, typeToAlias);
629 }
630 
631 void AliasInitializer::visit(Attribute attr, bool canBeDeferred) {
632   if (!visitedAttributes.insert(attr).second) {
633     // If this attribute already has an alias and this instance can't be
634     // deferred, make sure that the alias isn't deferred.
635     if (!canBeDeferred)
636       deferrableAttributes.erase(attr);
637     return;
638   }
639 
640   // Try to generate an alias for this attribute.
641   if (succeeded(generateAlias(attr, aliasToAttr))) {
642     if (canBeDeferred)
643       deferrableAttributes.insert(attr);
644     return;
645   }
646 
647   // Check for any sub elements.
648   if (auto subElementInterface = attr.dyn_cast<SubElementAttrInterface>()) {
649     subElementInterface.walkSubElements([&](Attribute attr) { visit(attr); },
650                                         [&](Type type) { visit(type); });
651   }
652 }
653 
654 void AliasInitializer::visit(Type type) {
655   if (!visitedTypes.insert(type).second)
656     return;
657 
658   // Try to generate an alias for this type.
659   if (succeeded(generateAlias(type, aliasToType)))
660     return;
661 
662   // Check for any sub elements.
663   if (auto subElementInterface = type.dyn_cast<SubElementTypeInterface>()) {
664     subElementInterface.walkSubElements([&](Attribute attr) { visit(attr); },
665                                         [&](Type type) { visit(type); });
666   }
667 }
668 
669 template <typename T>
670 LogicalResult AliasInitializer::generateAlias(
671     T symbol, llvm::MapVector<StringRef, std::vector<T>> &aliasToSymbol) {
672   SmallString<32> nameBuffer;
673   for (const auto &interface : interfaces) {
674     OpAsmDialectInterface::AliasResult result =
675         interface.getAlias(symbol, aliasOS);
676     if (result == OpAsmDialectInterface::AliasResult::NoAlias)
677       continue;
678     nameBuffer = std::move(aliasBuffer);
679     assert(!nameBuffer.empty() && "expected valid alias name");
680     if (result == OpAsmDialectInterface::AliasResult::FinalAlias)
681       break;
682   }
683 
684   if (nameBuffer.empty())
685     return failure();
686 
687   SmallString<16> tempBuffer;
688   StringRef name =
689       sanitizeIdentifier(nameBuffer, tempBuffer, /*allowedPunctChars=*/"$_-",
690                          /*allowTrailingDigit=*/false);
691   name = name.copy(aliasAllocator);
692   aliasToSymbol[name].push_back(symbol);
693   return success();
694 }
695 
696 //===----------------------------------------------------------------------===//
697 // AliasState
698 //===----------------------------------------------------------------------===//
699 
700 namespace {
701 /// This class manages the state for type and attribute aliases.
702 class AliasState {
703 public:
704   // Initialize the internal aliases.
705   void
706   initialize(Operation *op, const OpPrintingFlags &printerFlags,
707              DialectInterfaceCollection<OpAsmDialectInterface> &interfaces);
708 
709   /// Get an alias for the given attribute if it has one and print it in `os`.
710   /// Returns success if an alias was printed, failure otherwise.
711   LogicalResult getAlias(Attribute attr, raw_ostream &os) const;
712 
713   /// Get an alias for the given type if it has one and print it in `os`.
714   /// Returns success if an alias was printed, failure otherwise.
715   LogicalResult getAlias(Type ty, raw_ostream &os) const;
716 
717   /// Print all of the referenced aliases that can not be resolved in a deferred
718   /// manner.
719   void printNonDeferredAliases(raw_ostream &os, NewLineCounter &newLine) const {
720     printAliases(os, newLine, /*isDeferred=*/false);
721   }
722 
723   /// Print all of the referenced aliases that support deferred resolution.
724   void printDeferredAliases(raw_ostream &os, NewLineCounter &newLine) const {
725     printAliases(os, newLine, /*isDeferred=*/true);
726   }
727 
728 private:
729   /// Print all of the referenced aliases that support the provided resolution
730   /// behavior.
731   void printAliases(raw_ostream &os, NewLineCounter &newLine,
732                     bool isDeferred) const;
733 
734   /// Mapping between attribute and alias.
735   llvm::MapVector<Attribute, SymbolAlias> attrToAlias;
736   /// Mapping between type and alias.
737   llvm::MapVector<Type, SymbolAlias> typeToAlias;
738 
739   /// An allocator used for alias names.
740   llvm::BumpPtrAllocator aliasAllocator;
741 };
742 } // end anonymous namespace
743 
744 void AliasState::initialize(
745     Operation *op, const OpPrintingFlags &printerFlags,
746     DialectInterfaceCollection<OpAsmDialectInterface> &interfaces) {
747   AliasInitializer initializer(interfaces, aliasAllocator);
748   initializer.initialize(op, printerFlags, attrToAlias, typeToAlias);
749 }
750 
751 LogicalResult AliasState::getAlias(Attribute attr, raw_ostream &os) const {
752   auto it = attrToAlias.find(attr);
753   if (it == attrToAlias.end())
754     return failure();
755   it->second.print(os << '#');
756   return success();
757 }
758 
759 LogicalResult AliasState::getAlias(Type ty, raw_ostream &os) const {
760   auto it = typeToAlias.find(ty);
761   if (it == typeToAlias.end())
762     return failure();
763 
764   it->second.print(os << '!');
765   return success();
766 }
767 
768 void AliasState::printAliases(raw_ostream &os, NewLineCounter &newLine,
769                               bool isDeferred) const {
770   auto filterFn = [=](const auto &aliasIt) {
771     return aliasIt.second.canBeDeferred() == isDeferred;
772   };
773   for (const auto &it : llvm::make_filter_range(attrToAlias, filterFn)) {
774     it.second.print(os << '#');
775     os << " = " << it.first << newLine;
776   }
777   for (const auto &it : llvm::make_filter_range(typeToAlias, filterFn)) {
778     it.second.print(os << '!');
779     os << " = type " << it.first << newLine;
780   }
781 }
782 
783 //===----------------------------------------------------------------------===//
784 // SSANameState
785 //===----------------------------------------------------------------------===//
786 
787 namespace {
788 /// This class manages the state of SSA value names.
789 class SSANameState {
790 public:
791   /// A sentinel value used for values with names set.
792   enum : unsigned { NameSentinel = ~0U };
793 
794   SSANameState(Operation *op, const OpPrintingFlags &printerFlags,
795                DialectInterfaceCollection<OpAsmDialectInterface> &interfaces);
796 
797   /// Print the SSA identifier for the given value to 'stream'. If
798   /// 'printResultNo' is true, it also presents the result number ('#' number)
799   /// of this value.
800   void printValueID(Value value, bool printResultNo, raw_ostream &stream) const;
801 
802   /// Return the result indices for each of the result groups registered by this
803   /// operation, or empty if none exist.
804   ArrayRef<int> getOpResultGroups(Operation *op);
805 
806   /// Get the ID for the given block.
807   unsigned getBlockID(Block *block);
808 
809   /// Renumber the arguments for the specified region to the same names as the
810   /// SSA values in namesToUse. See OperationPrinter::shadowRegionArgs for
811   /// details.
812   void shadowRegionArgs(Region &region, ValueRange namesToUse);
813 
814 private:
815   /// Number the SSA values within the given IR unit.
816   void numberValuesInRegion(Region &region);
817   void numberValuesInBlock(Block &block);
818   void numberValuesInOp(Operation &op);
819 
820   /// Given a result of an operation 'result', find the result group head
821   /// 'lookupValue' and the result of 'result' within that group in
822   /// 'lookupResultNo'. 'lookupResultNo' is only filled in if the result group
823   /// has more than 1 result.
824   void getResultIDAndNumber(OpResult result, Value &lookupValue,
825                             Optional<int> &lookupResultNo) const;
826 
827   /// Set a special value name for the given value.
828   void setValueName(Value value, StringRef name);
829 
830   /// Uniques the given value name within the printer. If the given name
831   /// conflicts, it is automatically renamed.
832   StringRef uniqueValueName(StringRef name);
833 
834   /// This is the value ID for each SSA value. If this returns NameSentinel,
835   /// then the valueID has an entry in valueNames.
836   DenseMap<Value, unsigned> valueIDs;
837   DenseMap<Value, StringRef> valueNames;
838 
839   /// This is a map of operations that contain multiple named result groups,
840   /// i.e. there may be multiple names for the results of the operation. The
841   /// value of this map are the result numbers that start a result group.
842   DenseMap<Operation *, SmallVector<int, 1>> opResultGroups;
843 
844   /// This is the block ID for each block in the current.
845   DenseMap<Block *, unsigned> blockIDs;
846 
847   /// This keeps track of all of the non-numeric names that are in flight,
848   /// allowing us to check for duplicates.
849   /// Note: the value of the map is unused.
850   llvm::ScopedHashTable<StringRef, char> usedNames;
851   llvm::BumpPtrAllocator usedNameAllocator;
852 
853   /// This is the next value ID to assign in numbering.
854   unsigned nextValueID = 0;
855   /// This is the next ID to assign to a region entry block argument.
856   unsigned nextArgumentID = 0;
857   /// This is the next ID to assign when a name conflict is detected.
858   unsigned nextConflictID = 0;
859 
860   /// These are the printing flags.  They control, eg., whether to print in
861   /// generic form.
862   OpPrintingFlags printerFlags;
863 
864   DialectInterfaceCollection<OpAsmDialectInterface> &interfaces;
865 };
866 } // end anonymous namespace
867 
868 SSANameState::SSANameState(
869     Operation *op, const OpPrintingFlags &printerFlags,
870     DialectInterfaceCollection<OpAsmDialectInterface> &interfaces)
871     : printerFlags(printerFlags), interfaces(interfaces) {
872   llvm::SaveAndRestore<unsigned> valueIDSaver(nextValueID);
873   llvm::SaveAndRestore<unsigned> argumentIDSaver(nextArgumentID);
874   llvm::SaveAndRestore<unsigned> conflictIDSaver(nextConflictID);
875 
876   // The naming context includes `nextValueID`, `nextArgumentID`,
877   // `nextConflictID` and `usedNames` scoped HashTable. This information is
878   // carried from the parent region.
879   using UsedNamesScopeTy = llvm::ScopedHashTable<StringRef, char>::ScopeTy;
880   using NamingContext =
881       std::tuple<Region *, unsigned, unsigned, unsigned, UsedNamesScopeTy *>;
882 
883   // Allocator for UsedNamesScopeTy
884   llvm::BumpPtrAllocator allocator;
885 
886   // Add a scope for the top level operation.
887   auto *topLevelNamesScope =
888       new (allocator.Allocate<UsedNamesScopeTy>()) UsedNamesScopeTy(usedNames);
889 
890   SmallVector<NamingContext, 8> nameContext;
891   for (Region &region : op->getRegions())
892     nameContext.push_back(std::make_tuple(&region, nextValueID, nextArgumentID,
893                                           nextConflictID, topLevelNamesScope));
894 
895   numberValuesInOp(*op);
896 
897   while (!nameContext.empty()) {
898     Region *region;
899     UsedNamesScopeTy *parentScope;
900     std::tie(region, nextValueID, nextArgumentID, nextConflictID, parentScope) =
901         nameContext.pop_back_val();
902 
903     // When we switch from one subtree to another, pop the scopes(needless)
904     // until the parent scope.
905     while (usedNames.getCurScope() != parentScope) {
906       usedNames.getCurScope()->~UsedNamesScopeTy();
907       assert((usedNames.getCurScope() != nullptr || parentScope == nullptr) &&
908              "top level parentScope must be a nullptr");
909     }
910 
911     // Add a scope for the current region.
912     auto *curNamesScope = new (allocator.Allocate<UsedNamesScopeTy>())
913         UsedNamesScopeTy(usedNames);
914 
915     numberValuesInRegion(*region);
916 
917     for (Operation &op : region->getOps())
918       for (Region &region : op.getRegions())
919         nameContext.push_back(std::make_tuple(&region, nextValueID,
920                                               nextArgumentID, nextConflictID,
921                                               curNamesScope));
922   }
923 
924   // Manually remove all the scopes.
925   while (usedNames.getCurScope() != nullptr)
926     usedNames.getCurScope()->~UsedNamesScopeTy();
927 }
928 
929 void SSANameState::printValueID(Value value, bool printResultNo,
930                                 raw_ostream &stream) const {
931   if (!value) {
932     stream << "<<NULL>>";
933     return;
934   }
935 
936   Optional<int> resultNo;
937   auto lookupValue = value;
938 
939   // If this is an operation result, collect the head lookup value of the result
940   // group and the result number of 'result' within that group.
941   if (OpResult result = value.dyn_cast<OpResult>())
942     getResultIDAndNumber(result, lookupValue, resultNo);
943 
944   auto it = valueIDs.find(lookupValue);
945   if (it == valueIDs.end()) {
946     stream << "<<UNKNOWN SSA VALUE>>";
947     return;
948   }
949 
950   stream << '%';
951   if (it->second != NameSentinel) {
952     stream << it->second;
953   } else {
954     auto nameIt = valueNames.find(lookupValue);
955     assert(nameIt != valueNames.end() && "Didn't have a name entry?");
956     stream << nameIt->second;
957   }
958 
959   if (resultNo.hasValue() && printResultNo)
960     stream << '#' << resultNo;
961 }
962 
963 ArrayRef<int> SSANameState::getOpResultGroups(Operation *op) {
964   auto it = opResultGroups.find(op);
965   return it == opResultGroups.end() ? ArrayRef<int>() : it->second;
966 }
967 
968 unsigned SSANameState::getBlockID(Block *block) {
969   auto it = blockIDs.find(block);
970   return it != blockIDs.end() ? it->second : NameSentinel;
971 }
972 
973 void SSANameState::shadowRegionArgs(Region &region, ValueRange namesToUse) {
974   assert(!region.empty() && "cannot shadow arguments of an empty region");
975   assert(region.getNumArguments() == namesToUse.size() &&
976          "incorrect number of names passed in");
977   assert(region.getParentOp()->hasTrait<OpTrait::IsIsolatedFromAbove>() &&
978          "only KnownIsolatedFromAbove ops can shadow names");
979 
980   SmallVector<char, 16> nameStr;
981   for (unsigned i = 0, e = namesToUse.size(); i != e; ++i) {
982     auto nameToUse = namesToUse[i];
983     if (nameToUse == nullptr)
984       continue;
985     auto nameToReplace = region.getArgument(i);
986 
987     nameStr.clear();
988     llvm::raw_svector_ostream nameStream(nameStr);
989     printValueID(nameToUse, /*printResultNo=*/true, nameStream);
990 
991     // Entry block arguments should already have a pretty "arg" name.
992     assert(valueIDs[nameToReplace] == NameSentinel);
993 
994     // Use the name without the leading %.
995     auto name = StringRef(nameStream.str()).drop_front();
996 
997     // Overwrite the name.
998     valueNames[nameToReplace] = name.copy(usedNameAllocator);
999   }
1000 }
1001 
1002 void SSANameState::numberValuesInRegion(Region &region) {
1003   // Number the values within this region in a breadth-first order.
1004   unsigned nextBlockID = 0;
1005   for (auto &block : region) {
1006     // Each block gets a unique ID, and all of the operations within it get
1007     // numbered as well.
1008     blockIDs[&block] = nextBlockID++;
1009     numberValuesInBlock(block);
1010   }
1011 }
1012 
1013 void SSANameState::numberValuesInBlock(Block &block) {
1014   auto setArgNameFn = [&](Value arg, StringRef name) {
1015     assert(!valueIDs.count(arg) && "arg numbered multiple times");
1016     assert(arg.cast<BlockArgument>().getOwner() == &block &&
1017            "arg not defined in 'block'");
1018     setValueName(arg, name);
1019   };
1020 
1021   bool isEntryBlock = block.isEntryBlock();
1022   if (isEntryBlock && !printerFlags.shouldPrintGenericOpForm()) {
1023     if (auto *op = block.getParentOp()) {
1024       if (auto asmInterface = interfaces.getInterfaceFor(op->getDialect()))
1025         asmInterface->getAsmBlockArgumentNames(&block, setArgNameFn);
1026     }
1027   }
1028 
1029   // Number the block arguments. We give entry block arguments a special name
1030   // 'arg'.
1031   SmallString<32> specialNameBuffer(isEntryBlock ? "arg" : "");
1032   llvm::raw_svector_ostream specialName(specialNameBuffer);
1033   for (auto arg : block.getArguments()) {
1034     if (valueIDs.count(arg))
1035       continue;
1036     if (isEntryBlock) {
1037       specialNameBuffer.resize(strlen("arg"));
1038       specialName << nextArgumentID++;
1039     }
1040     setValueName(arg, specialName.str());
1041   }
1042 
1043   // Number the operations in this block.
1044   for (auto &op : block)
1045     numberValuesInOp(op);
1046 }
1047 
1048 void SSANameState::numberValuesInOp(Operation &op) {
1049   unsigned numResults = op.getNumResults();
1050   if (numResults == 0)
1051     return;
1052   Value resultBegin = op.getResult(0);
1053 
1054   // Function used to set the special result names for the operation.
1055   SmallVector<int, 2> resultGroups(/*Size=*/1, /*Value=*/0);
1056   auto setResultNameFn = [&](Value result, StringRef name) {
1057     assert(!valueIDs.count(result) && "result numbered multiple times");
1058     assert(result.getDefiningOp() == &op && "result not defined by 'op'");
1059     setValueName(result, name);
1060 
1061     // Record the result number for groups not anchored at 0.
1062     if (int resultNo = result.cast<OpResult>().getResultNumber())
1063       resultGroups.push_back(resultNo);
1064   };
1065   if (!printerFlags.shouldPrintGenericOpForm()) {
1066     if (OpAsmOpInterface asmInterface = dyn_cast<OpAsmOpInterface>(&op))
1067       asmInterface.getAsmResultNames(setResultNameFn);
1068     else if (auto *asmInterface = interfaces.getInterfaceFor(op.getDialect()))
1069       asmInterface->getAsmResultNames(&op, setResultNameFn);
1070   }
1071 
1072   // If the first result wasn't numbered, give it a default number.
1073   if (valueIDs.try_emplace(resultBegin, nextValueID).second)
1074     ++nextValueID;
1075 
1076   // If this operation has multiple result groups, mark it.
1077   if (resultGroups.size() != 1) {
1078     llvm::array_pod_sort(resultGroups.begin(), resultGroups.end());
1079     opResultGroups.try_emplace(&op, std::move(resultGroups));
1080   }
1081 }
1082 
1083 void SSANameState::getResultIDAndNumber(OpResult result, Value &lookupValue,
1084                                         Optional<int> &lookupResultNo) const {
1085   Operation *owner = result.getOwner();
1086   if (owner->getNumResults() == 1)
1087     return;
1088   int resultNo = result.getResultNumber();
1089 
1090   // If this operation has multiple result groups, we will need to find the
1091   // one corresponding to this result.
1092   auto resultGroupIt = opResultGroups.find(owner);
1093   if (resultGroupIt == opResultGroups.end()) {
1094     // If not, just use the first result.
1095     lookupResultNo = resultNo;
1096     lookupValue = owner->getResult(0);
1097     return;
1098   }
1099 
1100   // Find the correct index using a binary search, as the groups are ordered.
1101   ArrayRef<int> resultGroups = resultGroupIt->second;
1102   auto it = llvm::upper_bound(resultGroups, resultNo);
1103   int groupResultNo = 0, groupSize = 0;
1104 
1105   // If there are no smaller elements, the last result group is the lookup.
1106   if (it == resultGroups.end()) {
1107     groupResultNo = resultGroups.back();
1108     groupSize = static_cast<int>(owner->getNumResults()) - resultGroups.back();
1109   } else {
1110     // Otherwise, the previous element is the lookup.
1111     groupResultNo = *std::prev(it);
1112     groupSize = *it - groupResultNo;
1113   }
1114 
1115   // We only record the result number for a group of size greater than 1.
1116   if (groupSize != 1)
1117     lookupResultNo = resultNo - groupResultNo;
1118   lookupValue = owner->getResult(groupResultNo);
1119 }
1120 
1121 void SSANameState::setValueName(Value value, StringRef name) {
1122   // If the name is empty, the value uses the default numbering.
1123   if (name.empty()) {
1124     valueIDs[value] = nextValueID++;
1125     return;
1126   }
1127 
1128   valueIDs[value] = NameSentinel;
1129   valueNames[value] = uniqueValueName(name);
1130 }
1131 
1132 StringRef SSANameState::uniqueValueName(StringRef name) {
1133   SmallString<16> tmpBuffer;
1134   name = sanitizeIdentifier(name, tmpBuffer);
1135 
1136   // Check to see if this name is already unique.
1137   if (!usedNames.count(name)) {
1138     name = name.copy(usedNameAllocator);
1139   } else {
1140     // Otherwise, we had a conflict - probe until we find a unique name. This
1141     // is guaranteed to terminate (and usually in a single iteration) because it
1142     // generates new names by incrementing nextConflictID.
1143     SmallString<64> probeName(name);
1144     probeName.push_back('_');
1145     while (true) {
1146       probeName += llvm::utostr(nextConflictID++);
1147       if (!usedNames.count(probeName)) {
1148         name = probeName.str().copy(usedNameAllocator);
1149         break;
1150       }
1151       probeName.resize(name.size() + 1);
1152     }
1153   }
1154 
1155   usedNames.insert(name, char());
1156   return name;
1157 }
1158 
1159 //===----------------------------------------------------------------------===//
1160 // AsmState
1161 //===----------------------------------------------------------------------===//
1162 
1163 namespace mlir {
1164 namespace detail {
1165 class AsmStateImpl {
1166 public:
1167   explicit AsmStateImpl(Operation *op, const OpPrintingFlags &printerFlags,
1168                         AsmState::LocationMap *locationMap)
1169       : interfaces(op->getContext()), nameState(op, printerFlags, interfaces),
1170         printerFlags(printerFlags), locationMap(locationMap) {}
1171 
1172   /// Initialize the alias state to enable the printing of aliases.
1173   void initializeAliases(Operation *op) {
1174     aliasState.initialize(op, printerFlags, interfaces);
1175   }
1176 
1177   /// Get an instance of the OpAsmDialectInterface for the given dialect, or
1178   /// null if one wasn't registered.
1179   const OpAsmDialectInterface *getOpAsmInterface(Dialect *dialect) {
1180     return interfaces.getInterfaceFor(dialect);
1181   }
1182 
1183   /// Get the state used for aliases.
1184   AliasState &getAliasState() { return aliasState; }
1185 
1186   /// Get the state used for SSA names.
1187   SSANameState &getSSANameState() { return nameState; }
1188 
1189   /// Register the location, line and column, within the buffer that the given
1190   /// operation was printed at.
1191   void registerOperationLocation(Operation *op, unsigned line, unsigned col) {
1192     if (locationMap)
1193       (*locationMap)[op] = std::make_pair(line, col);
1194   }
1195 
1196 private:
1197   /// Collection of OpAsm interfaces implemented in the context.
1198   DialectInterfaceCollection<OpAsmDialectInterface> interfaces;
1199 
1200   /// The state used for attribute and type aliases.
1201   AliasState aliasState;
1202 
1203   /// The state used for SSA value names.
1204   SSANameState nameState;
1205 
1206   /// Flags that control op output.
1207   OpPrintingFlags printerFlags;
1208 
1209   /// An optional location map to be populated.
1210   AsmState::LocationMap *locationMap;
1211 };
1212 } // end namespace detail
1213 } // end namespace mlir
1214 
1215 AsmState::AsmState(Operation *op, const OpPrintingFlags &printerFlags,
1216                    LocationMap *locationMap)
1217     : impl(std::make_unique<AsmStateImpl>(op, printerFlags, locationMap)) {}
1218 AsmState::~AsmState() {}
1219 
1220 //===----------------------------------------------------------------------===//
1221 // AsmPrinter::Impl
1222 //===----------------------------------------------------------------------===//
1223 
1224 namespace mlir {
1225 class AsmPrinter::Impl {
1226 public:
1227   Impl(raw_ostream &os, OpPrintingFlags flags = llvm::None,
1228        AsmStateImpl *state = nullptr)
1229       : os(os), printerFlags(flags), state(state) {}
1230   explicit Impl(Impl &other)
1231       : Impl(other.os, other.printerFlags, other.state) {}
1232 
1233   /// Returns the output stream of the printer.
1234   raw_ostream &getStream() { return os; }
1235 
1236   template <typename Container, typename UnaryFunctor>
1237   inline void interleaveComma(const Container &c, UnaryFunctor each_fn) const {
1238     llvm::interleaveComma(c, os, each_fn);
1239   }
1240 
1241   /// This enum describes the different kinds of elision for the type of an
1242   /// attribute when printing it.
1243   enum class AttrTypeElision {
1244     /// The type must not be elided,
1245     Never,
1246     /// The type may be elided when it matches the default used in the parser
1247     /// (for example i64 is the default for integer attributes).
1248     May,
1249     /// The type must be elided.
1250     Must
1251   };
1252 
1253   /// Print the given attribute.
1254   void printAttribute(Attribute attr,
1255                       AttrTypeElision typeElision = AttrTypeElision::Never);
1256 
1257   void printType(Type type);
1258 
1259   /// Print the given location to the stream. If `allowAlias` is true, this
1260   /// allows for the internal location to use an attribute alias.
1261   void printLocation(LocationAttr loc, bool allowAlias = false);
1262 
1263   void printAffineMap(AffineMap map);
1264   void
1265   printAffineExpr(AffineExpr expr,
1266                   function_ref<void(unsigned, bool)> printValueName = nullptr);
1267   void printAffineConstraint(AffineExpr expr, bool isEq);
1268   void printIntegerSet(IntegerSet set);
1269 
1270 protected:
1271   void printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
1272                              ArrayRef<StringRef> elidedAttrs = {},
1273                              bool withKeyword = false);
1274   void printNamedAttribute(NamedAttribute attr);
1275   void printTrailingLocation(Location loc, bool allowAlias = true);
1276   void printLocationInternal(LocationAttr loc, bool pretty = false);
1277 
1278   /// Print a dense elements attribute. If 'allowHex' is true, a hex string is
1279   /// used instead of individual elements when the elements attr is large.
1280   void printDenseElementsAttr(DenseElementsAttr attr, bool allowHex);
1281 
1282   /// Print a dense string elements attribute.
1283   void printDenseStringElementsAttr(DenseStringElementsAttr attr);
1284 
1285   /// Print a dense elements attribute. If 'allowHex' is true, a hex string is
1286   /// used instead of individual elements when the elements attr is large.
1287   void printDenseIntOrFPElementsAttr(DenseIntOrFPElementsAttr attr,
1288                                      bool allowHex);
1289 
1290   void printDialectAttribute(Attribute attr);
1291   void printDialectType(Type type);
1292 
1293   /// This enum is used to represent the binding strength of the enclosing
1294   /// context that an AffineExprStorage is being printed in, so we can
1295   /// intelligently produce parens.
1296   enum class BindingStrength {
1297     Weak,   // + and -
1298     Strong, // All other binary operators.
1299   };
1300   void printAffineExprInternal(
1301       AffineExpr expr, BindingStrength enclosingTightness,
1302       function_ref<void(unsigned, bool)> printValueName = nullptr);
1303 
1304   /// The output stream for the printer.
1305   raw_ostream &os;
1306 
1307   /// A set of flags to control the printer's behavior.
1308   OpPrintingFlags printerFlags;
1309 
1310   /// An optional printer state for the module.
1311   AsmStateImpl *state;
1312 
1313   /// A tracker for the number of new lines emitted during printing.
1314   NewLineCounter newLine;
1315 };
1316 } // namespace mlir
1317 
1318 void AsmPrinter::Impl::printTrailingLocation(Location loc, bool allowAlias) {
1319   // Check to see if we are printing debug information.
1320   if (!printerFlags.shouldPrintDebugInfo())
1321     return;
1322 
1323   os << " ";
1324   printLocation(loc, /*allowAlias=*/allowAlias);
1325 }
1326 
1327 void AsmPrinter::Impl::printLocationInternal(LocationAttr loc, bool pretty) {
1328   TypeSwitch<LocationAttr>(loc)
1329       .Case<OpaqueLoc>([&](OpaqueLoc loc) {
1330         printLocationInternal(loc.getFallbackLocation(), pretty);
1331       })
1332       .Case<UnknownLoc>([&](UnknownLoc loc) {
1333         if (pretty)
1334           os << "[unknown]";
1335         else
1336           os << "unknown";
1337       })
1338       .Case<FileLineColLoc>([&](FileLineColLoc loc) {
1339         if (pretty) {
1340           os << loc.getFilename();
1341         } else {
1342           os << "\"";
1343           printEscapedString(loc.getFilename(), os);
1344           os << "\"";
1345         }
1346         os << ':' << loc.getLine() << ':' << loc.getColumn();
1347       })
1348       .Case<NameLoc>([&](NameLoc loc) {
1349         os << '\"';
1350         printEscapedString(loc.getName(), os);
1351         os << '\"';
1352 
1353         // Print the child if it isn't unknown.
1354         auto childLoc = loc.getChildLoc();
1355         if (!childLoc.isa<UnknownLoc>()) {
1356           os << '(';
1357           printLocationInternal(childLoc, pretty);
1358           os << ')';
1359         }
1360       })
1361       .Case<CallSiteLoc>([&](CallSiteLoc loc) {
1362         Location caller = loc.getCaller();
1363         Location callee = loc.getCallee();
1364         if (!pretty)
1365           os << "callsite(";
1366         printLocationInternal(callee, pretty);
1367         if (pretty) {
1368           if (callee.isa<NameLoc>()) {
1369             if (caller.isa<FileLineColLoc>()) {
1370               os << " at ";
1371             } else {
1372               os << newLine << " at ";
1373             }
1374           } else {
1375             os << newLine << " at ";
1376           }
1377         } else {
1378           os << " at ";
1379         }
1380         printLocationInternal(caller, pretty);
1381         if (!pretty)
1382           os << ")";
1383       })
1384       .Case<FusedLoc>([&](FusedLoc loc) {
1385         if (!pretty)
1386           os << "fused";
1387         if (Attribute metadata = loc.getMetadata())
1388           os << '<' << metadata << '>';
1389         os << '[';
1390         interleave(
1391             loc.getLocations(),
1392             [&](Location loc) { printLocationInternal(loc, pretty); },
1393             [&]() { os << ", "; });
1394         os << ']';
1395       });
1396 }
1397 
1398 /// Print a floating point value in a way that the parser will be able to
1399 /// round-trip losslessly.
1400 static void printFloatValue(const APFloat &apValue, raw_ostream &os) {
1401   // We would like to output the FP constant value in exponential notation,
1402   // but we cannot do this if doing so will lose precision.  Check here to
1403   // make sure that we only output it in exponential format if we can parse
1404   // the value back and get the same value.
1405   bool isInf = apValue.isInfinity();
1406   bool isNaN = apValue.isNaN();
1407   if (!isInf && !isNaN) {
1408     SmallString<128> strValue;
1409     apValue.toString(strValue, /*FormatPrecision=*/6, /*FormatMaxPadding=*/0,
1410                      /*TruncateZero=*/false);
1411 
1412     // Check to make sure that the stringized number is not some string like
1413     // "Inf" or NaN, that atof will accept, but the lexer will not.  Check
1414     // that the string matches the "[-+]?[0-9]" regex.
1415     assert(((strValue[0] >= '0' && strValue[0] <= '9') ||
1416             ((strValue[0] == '-' || strValue[0] == '+') &&
1417              (strValue[1] >= '0' && strValue[1] <= '9'))) &&
1418            "[-+]?[0-9] regex does not match!");
1419 
1420     // Parse back the stringized version and check that the value is equal
1421     // (i.e., there is no precision loss).
1422     if (APFloat(apValue.getSemantics(), strValue).bitwiseIsEqual(apValue)) {
1423       os << strValue;
1424       return;
1425     }
1426 
1427     // If it is not, use the default format of APFloat instead of the
1428     // exponential notation.
1429     strValue.clear();
1430     apValue.toString(strValue);
1431 
1432     // Make sure that we can parse the default form as a float.
1433     if (strValue.str().contains('.')) {
1434       os << strValue;
1435       return;
1436     }
1437   }
1438 
1439   // Print special values in hexadecimal format. The sign bit should be included
1440   // in the literal.
1441   SmallVector<char, 16> str;
1442   APInt apInt = apValue.bitcastToAPInt();
1443   apInt.toString(str, /*Radix=*/16, /*Signed=*/false,
1444                  /*formatAsCLiteral=*/true);
1445   os << str;
1446 }
1447 
1448 void AsmPrinter::Impl::printLocation(LocationAttr loc, bool allowAlias) {
1449   if (printerFlags.shouldPrintDebugInfoPrettyForm())
1450     return printLocationInternal(loc, /*pretty=*/true);
1451 
1452   os << "loc(";
1453   if (!allowAlias || !state || failed(state->getAliasState().getAlias(loc, os)))
1454     printLocationInternal(loc);
1455   os << ')';
1456 }
1457 
1458 /// Returns true if the given dialect symbol data is simple enough to print in
1459 /// the pretty form, i.e. without the enclosing "".
1460 static bool isDialectSymbolSimpleEnoughForPrettyForm(StringRef symName) {
1461   // The name must start with an identifier.
1462   if (symName.empty() || !isalpha(symName.front()))
1463     return false;
1464 
1465   // Ignore all the characters that are valid in an identifier in the symbol
1466   // name.
1467   symName = symName.drop_while(
1468       [](char c) { return llvm::isAlnum(c) || c == '.' || c == '_'; });
1469   if (symName.empty())
1470     return true;
1471 
1472   // If we got to an unexpected character, then it must be a <>.  Check those
1473   // recursively.
1474   if (symName.front() != '<' || symName.back() != '>')
1475     return false;
1476 
1477   SmallVector<char, 8> nestedPunctuation;
1478   do {
1479     // If we ran out of characters, then we had a punctuation mismatch.
1480     if (symName.empty())
1481       return false;
1482 
1483     auto c = symName.front();
1484     symName = symName.drop_front();
1485 
1486     switch (c) {
1487     // We never allow null characters. This is an EOF indicator for the lexer
1488     // which we could handle, but isn't important for any known dialect.
1489     case '\0':
1490       return false;
1491     case '<':
1492     case '[':
1493     case '(':
1494     case '{':
1495       nestedPunctuation.push_back(c);
1496       continue;
1497     case '-':
1498       // Treat `->` as a special token.
1499       if (!symName.empty() && symName.front() == '>') {
1500         symName = symName.drop_front();
1501         continue;
1502       }
1503       break;
1504     // Reject types with mismatched brackets.
1505     case '>':
1506       if (nestedPunctuation.pop_back_val() != '<')
1507         return false;
1508       break;
1509     case ']':
1510       if (nestedPunctuation.pop_back_val() != '[')
1511         return false;
1512       break;
1513     case ')':
1514       if (nestedPunctuation.pop_back_val() != '(')
1515         return false;
1516       break;
1517     case '}':
1518       if (nestedPunctuation.pop_back_val() != '{')
1519         return false;
1520       break;
1521     default:
1522       continue;
1523     }
1524 
1525     // We're done when the punctuation is fully matched.
1526   } while (!nestedPunctuation.empty());
1527 
1528   // If there were extra characters, then we failed.
1529   return symName.empty();
1530 }
1531 
1532 /// Print the given dialect symbol to the stream.
1533 static void printDialectSymbol(raw_ostream &os, StringRef symPrefix,
1534                                StringRef dialectName, StringRef symString) {
1535   os << symPrefix << dialectName;
1536 
1537   // If this symbol name is simple enough, print it directly in pretty form,
1538   // otherwise, we print it as an escaped string.
1539   if (isDialectSymbolSimpleEnoughForPrettyForm(symString)) {
1540     os << '.' << symString;
1541     return;
1542   }
1543 
1544   os << "<\"";
1545   llvm::printEscapedString(symString, os);
1546   os << "\">";
1547 }
1548 
1549 /// Returns true if the given string can be represented as a bare identifier.
1550 static bool isBareIdentifier(StringRef name) {
1551   assert(!name.empty() && "invalid name");
1552 
1553   // By making this unsigned, the value passed in to isalnum will always be
1554   // in the range 0-255. This is important when building with MSVC because
1555   // its implementation will assert. This situation can arise when dealing
1556   // with UTF-8 multibyte characters.
1557   unsigned char firstChar = static_cast<unsigned char>(name[0]);
1558   if (!isalpha(firstChar) && firstChar != '_')
1559     return false;
1560   return llvm::all_of(name.drop_front(), [](unsigned char c) {
1561     return isalnum(c) || c == '_' || c == '$' || c == '.';
1562   });
1563 }
1564 
1565 /// Print the given string as a symbol reference. A symbol reference is
1566 /// represented as a string prefixed with '@'. The reference is surrounded with
1567 /// ""'s and escaped if it has any special or non-printable characters in it.
1568 static void printSymbolReference(StringRef symbolRef, raw_ostream &os) {
1569   assert(!symbolRef.empty() && "expected valid symbol reference");
1570 
1571   // If the symbol can be represented as a bare identifier, write it directly.
1572   if (isBareIdentifier(symbolRef)) {
1573     os << '@' << symbolRef;
1574     return;
1575   }
1576 
1577   // Otherwise, output the reference wrapped in quotes with proper escaping.
1578   os << "@\"";
1579   printEscapedString(symbolRef, os);
1580   os << '"';
1581 }
1582 
1583 // Print out a valid ElementsAttr that is succinct and can represent any
1584 // potential shape/type, for use when eliding a large ElementsAttr.
1585 //
1586 // We choose to use an opaque ElementsAttr literal with conspicuous content to
1587 // hopefully alert readers to the fact that this has been elided.
1588 //
1589 // Unfortunately, neither of the strings of an opaque ElementsAttr literal will
1590 // accept the string "elided". The first string must be a registered dialect
1591 // name and the latter must be a hex constant.
1592 static void printElidedElementsAttr(raw_ostream &os) {
1593   os << R"(opaque<"_", "0xDEADBEEF">)";
1594 }
1595 
1596 void AsmPrinter::Impl::printAttribute(Attribute attr,
1597                                       AttrTypeElision typeElision) {
1598   if (!attr) {
1599     os << "<<NULL ATTRIBUTE>>";
1600     return;
1601   }
1602 
1603   // Try to print an alias for this attribute.
1604   if (state && succeeded(state->getAliasState().getAlias(attr, os)))
1605     return;
1606 
1607   auto attrType = attr.getType();
1608   if (auto opaqueAttr = attr.dyn_cast<OpaqueAttr>()) {
1609     printDialectSymbol(os, "#", opaqueAttr.getDialectNamespace(),
1610                        opaqueAttr.getAttrData());
1611   } else if (attr.isa<UnitAttr>()) {
1612     os << "unit";
1613     return;
1614   } else if (auto dictAttr = attr.dyn_cast<DictionaryAttr>()) {
1615     os << '{';
1616     interleaveComma(dictAttr.getValue(),
1617                     [&](NamedAttribute attr) { printNamedAttribute(attr); });
1618     os << '}';
1619 
1620   } else if (auto intAttr = attr.dyn_cast<IntegerAttr>()) {
1621     if (attrType.isSignlessInteger(1)) {
1622       os << (intAttr.getValue().getBoolValue() ? "true" : "false");
1623 
1624       // Boolean integer attributes always elides the type.
1625       return;
1626     }
1627 
1628     // Only print attributes as unsigned if they are explicitly unsigned or are
1629     // signless 1-bit values.  Indexes, signed values, and multi-bit signless
1630     // values print as signed.
1631     bool isUnsigned =
1632         attrType.isUnsignedInteger() || attrType.isSignlessInteger(1);
1633     intAttr.getValue().print(os, !isUnsigned);
1634 
1635     // IntegerAttr elides the type if I64.
1636     if (typeElision == AttrTypeElision::May && attrType.isSignlessInteger(64))
1637       return;
1638 
1639   } else if (auto floatAttr = attr.dyn_cast<FloatAttr>()) {
1640     printFloatValue(floatAttr.getValue(), os);
1641 
1642     // FloatAttr elides the type if F64.
1643     if (typeElision == AttrTypeElision::May && attrType.isF64())
1644       return;
1645 
1646   } else if (auto strAttr = attr.dyn_cast<StringAttr>()) {
1647     os << '"';
1648     printEscapedString(strAttr.getValue(), os);
1649     os << '"';
1650 
1651   } else if (auto arrayAttr = attr.dyn_cast<ArrayAttr>()) {
1652     os << '[';
1653     interleaveComma(arrayAttr.getValue(), [&](Attribute attr) {
1654       printAttribute(attr, AttrTypeElision::May);
1655     });
1656     os << ']';
1657 
1658   } else if (auto affineMapAttr = attr.dyn_cast<AffineMapAttr>()) {
1659     os << "affine_map<";
1660     affineMapAttr.getValue().print(os);
1661     os << '>';
1662 
1663     // AffineMap always elides the type.
1664     return;
1665 
1666   } else if (auto integerSetAttr = attr.dyn_cast<IntegerSetAttr>()) {
1667     os << "affine_set<";
1668     integerSetAttr.getValue().print(os);
1669     os << '>';
1670 
1671     // IntegerSet always elides the type.
1672     return;
1673 
1674   } else if (auto typeAttr = attr.dyn_cast<TypeAttr>()) {
1675     printType(typeAttr.getValue());
1676 
1677   } else if (auto refAttr = attr.dyn_cast<SymbolRefAttr>()) {
1678     printSymbolReference(refAttr.getRootReference().getValue(), os);
1679     for (FlatSymbolRefAttr nestedRef : refAttr.getNestedReferences()) {
1680       os << "::";
1681       printSymbolReference(nestedRef.getValue(), os);
1682     }
1683 
1684   } else if (auto opaqueAttr = attr.dyn_cast<OpaqueElementsAttr>()) {
1685     if (printerFlags.shouldElideElementsAttr(opaqueAttr)) {
1686       printElidedElementsAttr(os);
1687     } else {
1688       os << "opaque<\"" << opaqueAttr.getDialect() << "\", \"0x"
1689          << llvm::toHex(opaqueAttr.getValue()) << "\">";
1690     }
1691 
1692   } else if (auto intOrFpEltAttr = attr.dyn_cast<DenseIntOrFPElementsAttr>()) {
1693     if (printerFlags.shouldElideElementsAttr(intOrFpEltAttr)) {
1694       printElidedElementsAttr(os);
1695     } else {
1696       os << "dense<";
1697       printDenseIntOrFPElementsAttr(intOrFpEltAttr, /*allowHex=*/true);
1698       os << '>';
1699     }
1700 
1701   } else if (auto strEltAttr = attr.dyn_cast<DenseStringElementsAttr>()) {
1702     if (printerFlags.shouldElideElementsAttr(strEltAttr)) {
1703       printElidedElementsAttr(os);
1704     } else {
1705       os << "dense<";
1706       printDenseStringElementsAttr(strEltAttr);
1707       os << '>';
1708     }
1709 
1710   } else if (auto sparseEltAttr = attr.dyn_cast<SparseElementsAttr>()) {
1711     if (printerFlags.shouldElideElementsAttr(sparseEltAttr.getIndices()) ||
1712         printerFlags.shouldElideElementsAttr(sparseEltAttr.getValues())) {
1713       printElidedElementsAttr(os);
1714     } else {
1715       os << "sparse<";
1716       DenseIntElementsAttr indices = sparseEltAttr.getIndices();
1717       if (indices.getNumElements() != 0) {
1718         printDenseIntOrFPElementsAttr(indices, /*allowHex=*/false);
1719         os << ", ";
1720         printDenseElementsAttr(sparseEltAttr.getValues(), /*allowHex=*/true);
1721       }
1722       os << '>';
1723     }
1724 
1725   } else if (auto locAttr = attr.dyn_cast<LocationAttr>()) {
1726     printLocation(locAttr);
1727 
1728   } else {
1729     return printDialectAttribute(attr);
1730   }
1731 
1732   // Don't print the type if we must elide it, or if it is a None type.
1733   if (typeElision != AttrTypeElision::Must && !attrType.isa<NoneType>()) {
1734     os << " : ";
1735     printType(attrType);
1736   }
1737 }
1738 
1739 /// Print the integer element of a DenseElementsAttr.
1740 static void printDenseIntElement(const APInt &value, raw_ostream &os,
1741                                  bool isSigned) {
1742   if (value.getBitWidth() == 1)
1743     os << (value.getBoolValue() ? "true" : "false");
1744   else
1745     value.print(os, isSigned);
1746 }
1747 
1748 static void
1749 printDenseElementsAttrImpl(bool isSplat, ShapedType type, raw_ostream &os,
1750                            function_ref<void(unsigned)> printEltFn) {
1751   // Special case for 0-d and splat tensors.
1752   if (isSplat)
1753     return printEltFn(0);
1754 
1755   // Special case for degenerate tensors.
1756   auto numElements = type.getNumElements();
1757   if (numElements == 0)
1758     return;
1759 
1760   // We use a mixed-radix counter to iterate through the shape. When we bump a
1761   // non-least-significant digit, we emit a close bracket. When we next emit an
1762   // element we re-open all closed brackets.
1763 
1764   // The mixed-radix counter, with radices in 'shape'.
1765   int64_t rank = type.getRank();
1766   SmallVector<unsigned, 4> counter(rank, 0);
1767   // The number of brackets that have been opened and not closed.
1768   unsigned openBrackets = 0;
1769 
1770   auto shape = type.getShape();
1771   auto bumpCounter = [&] {
1772     // Bump the least significant digit.
1773     ++counter[rank - 1];
1774     // Iterate backwards bubbling back the increment.
1775     for (unsigned i = rank - 1; i > 0; --i)
1776       if (counter[i] >= shape[i]) {
1777         // Index 'i' is rolled over. Bump (i-1) and close a bracket.
1778         counter[i] = 0;
1779         ++counter[i - 1];
1780         --openBrackets;
1781         os << ']';
1782       }
1783   };
1784 
1785   for (unsigned idx = 0, e = numElements; idx != e; ++idx) {
1786     if (idx != 0)
1787       os << ", ";
1788     while (openBrackets++ < rank)
1789       os << '[';
1790     openBrackets = rank;
1791     printEltFn(idx);
1792     bumpCounter();
1793   }
1794   while (openBrackets-- > 0)
1795     os << ']';
1796 }
1797 
1798 void AsmPrinter::Impl::printDenseElementsAttr(DenseElementsAttr attr,
1799                                               bool allowHex) {
1800   if (auto stringAttr = attr.dyn_cast<DenseStringElementsAttr>())
1801     return printDenseStringElementsAttr(stringAttr);
1802 
1803   printDenseIntOrFPElementsAttr(attr.cast<DenseIntOrFPElementsAttr>(),
1804                                 allowHex);
1805 }
1806 
1807 void AsmPrinter::Impl::printDenseIntOrFPElementsAttr(
1808     DenseIntOrFPElementsAttr attr, bool allowHex) {
1809   auto type = attr.getType();
1810   auto elementType = type.getElementType();
1811 
1812   // Check to see if we should format this attribute as a hex string.
1813   auto numElements = type.getNumElements();
1814   if (!attr.isSplat() && allowHex &&
1815       shouldPrintElementsAttrWithHex(numElements)) {
1816     ArrayRef<char> rawData = attr.getRawData();
1817     if (llvm::support::endian::system_endianness() ==
1818         llvm::support::endianness::big) {
1819       // Convert endianess in big-endian(BE) machines. `rawData` is BE in BE
1820       // machines. It is converted here to print in LE format.
1821       SmallVector<char, 64> outDataVec(rawData.size());
1822       MutableArrayRef<char> convRawData(outDataVec);
1823       DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
1824           rawData, convRawData, type);
1825       os << '"' << "0x"
1826          << llvm::toHex(StringRef(convRawData.data(), convRawData.size()))
1827          << "\"";
1828     } else {
1829       os << '"' << "0x"
1830          << llvm::toHex(StringRef(rawData.data(), rawData.size())) << "\"";
1831     }
1832 
1833     return;
1834   }
1835 
1836   if (ComplexType complexTy = elementType.dyn_cast<ComplexType>()) {
1837     Type complexElementType = complexTy.getElementType();
1838     // Note: The if and else below had a common lambda function which invoked
1839     // printDenseElementsAttrImpl. This lambda was hitting a bug in gcc 9.1,9.2
1840     // and hence was replaced.
1841     if (complexElementType.isa<IntegerType>()) {
1842       bool isSigned = !complexElementType.isUnsignedInteger();
1843       auto valueIt = attr.value_begin<std::complex<APInt>>();
1844       printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
1845         auto complexValue = *(valueIt + index);
1846         os << "(";
1847         printDenseIntElement(complexValue.real(), os, isSigned);
1848         os << ",";
1849         printDenseIntElement(complexValue.imag(), os, isSigned);
1850         os << ")";
1851       });
1852     } else {
1853       auto valueIt = attr.value_begin<std::complex<APFloat>>();
1854       printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
1855         auto complexValue = *(valueIt + index);
1856         os << "(";
1857         printFloatValue(complexValue.real(), os);
1858         os << ",";
1859         printFloatValue(complexValue.imag(), os);
1860         os << ")";
1861       });
1862     }
1863   } else if (elementType.isIntOrIndex()) {
1864     bool isSigned = !elementType.isUnsignedInteger();
1865     auto valueIt = attr.value_begin<APInt>();
1866     printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
1867       printDenseIntElement(*(valueIt + index), os, isSigned);
1868     });
1869   } else {
1870     assert(elementType.isa<FloatType>() && "unexpected element type");
1871     auto valueIt = attr.value_begin<APFloat>();
1872     printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
1873       printFloatValue(*(valueIt + index), os);
1874     });
1875   }
1876 }
1877 
1878 void AsmPrinter::Impl::printDenseStringElementsAttr(
1879     DenseStringElementsAttr attr) {
1880   ArrayRef<StringRef> data = attr.getRawStringData();
1881   auto printFn = [&](unsigned index) {
1882     os << "\"";
1883     printEscapedString(data[index], os);
1884     os << "\"";
1885   };
1886   printDenseElementsAttrImpl(attr.isSplat(), attr.getType(), os, printFn);
1887 }
1888 
1889 void AsmPrinter::Impl::printType(Type type) {
1890   if (!type) {
1891     os << "<<NULL TYPE>>";
1892     return;
1893   }
1894 
1895   // Try to print an alias for this type.
1896   if (state && succeeded(state->getAliasState().getAlias(type, os)))
1897     return;
1898 
1899   TypeSwitch<Type>(type)
1900       .Case<OpaqueType>([&](OpaqueType opaqueTy) {
1901         printDialectSymbol(os, "!", opaqueTy.getDialectNamespace(),
1902                            opaqueTy.getTypeData());
1903       })
1904       .Case<IndexType>([&](Type) { os << "index"; })
1905       .Case<BFloat16Type>([&](Type) { os << "bf16"; })
1906       .Case<Float16Type>([&](Type) { os << "f16"; })
1907       .Case<Float32Type>([&](Type) { os << "f32"; })
1908       .Case<Float64Type>([&](Type) { os << "f64"; })
1909       .Case<Float80Type>([&](Type) { os << "f80"; })
1910       .Case<Float128Type>([&](Type) { os << "f128"; })
1911       .Case<IntegerType>([&](IntegerType integerTy) {
1912         if (integerTy.isSigned())
1913           os << 's';
1914         else if (integerTy.isUnsigned())
1915           os << 'u';
1916         os << 'i' << integerTy.getWidth();
1917       })
1918       .Case<FunctionType>([&](FunctionType funcTy) {
1919         os << '(';
1920         interleaveComma(funcTy.getInputs(), [&](Type ty) { printType(ty); });
1921         os << ") -> ";
1922         ArrayRef<Type> results = funcTy.getResults();
1923         if (results.size() == 1 && !results[0].isa<FunctionType>()) {
1924           os << results[0];
1925         } else {
1926           os << '(';
1927           interleaveComma(results, [&](Type ty) { printType(ty); });
1928           os << ')';
1929         }
1930       })
1931       .Case<VectorType>([&](VectorType vectorTy) {
1932         os << "vector<";
1933         for (int64_t dim : vectorTy.getShape())
1934           os << dim << 'x';
1935         os << vectorTy.getElementType() << '>';
1936       })
1937       .Case<RankedTensorType>([&](RankedTensorType tensorTy) {
1938         os << "tensor<";
1939         for (int64_t dim : tensorTy.getShape()) {
1940           if (ShapedType::isDynamic(dim))
1941             os << '?';
1942           else
1943             os << dim;
1944           os << 'x';
1945         }
1946         os << tensorTy.getElementType();
1947         // Only print the encoding attribute value if set.
1948         if (tensorTy.getEncoding()) {
1949           os << ", ";
1950           printAttribute(tensorTy.getEncoding());
1951         }
1952         os << '>';
1953       })
1954       .Case<UnrankedTensorType>([&](UnrankedTensorType tensorTy) {
1955         os << "tensor<*x";
1956         printType(tensorTy.getElementType());
1957         os << '>';
1958       })
1959       .Case<MemRefType>([&](MemRefType memrefTy) {
1960         os << "memref<";
1961         for (int64_t dim : memrefTy.getShape()) {
1962           if (ShapedType::isDynamic(dim))
1963             os << '?';
1964           else
1965             os << dim;
1966           os << 'x';
1967         }
1968         printType(memrefTy.getElementType());
1969         for (auto map : memrefTy.getAffineMaps()) {
1970           os << ", ";
1971           printAttribute(AffineMapAttr::get(map));
1972         }
1973         // Only print the memory space if it is the non-default one.
1974         if (memrefTy.getMemorySpace()) {
1975           os << ", ";
1976           printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
1977         }
1978         os << '>';
1979       })
1980       .Case<UnrankedMemRefType>([&](UnrankedMemRefType memrefTy) {
1981         os << "memref<*x";
1982         printType(memrefTy.getElementType());
1983         // Only print the memory space if it is the non-default one.
1984         if (memrefTy.getMemorySpace()) {
1985           os << ", ";
1986           printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
1987         }
1988         os << '>';
1989       })
1990       .Case<ComplexType>([&](ComplexType complexTy) {
1991         os << "complex<";
1992         printType(complexTy.getElementType());
1993         os << '>';
1994       })
1995       .Case<TupleType>([&](TupleType tupleTy) {
1996         os << "tuple<";
1997         interleaveComma(tupleTy.getTypes(),
1998                         [&](Type type) { printType(type); });
1999         os << '>';
2000       })
2001       .Case<NoneType>([&](Type) { os << "none"; })
2002       .Default([&](Type type) { return printDialectType(type); });
2003 }
2004 
2005 void AsmPrinter::Impl::printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
2006                                              ArrayRef<StringRef> elidedAttrs,
2007                                              bool withKeyword) {
2008   // If there are no attributes, then there is nothing to be done.
2009   if (attrs.empty())
2010     return;
2011 
2012   // Functor used to print a filtered attribute list.
2013   auto printFilteredAttributesFn = [&](auto filteredAttrs) {
2014     // Print the 'attributes' keyword if necessary.
2015     if (withKeyword)
2016       os << " attributes";
2017 
2018     // Otherwise, print them all out in braces.
2019     os << " {";
2020     interleaveComma(filteredAttrs,
2021                     [&](NamedAttribute attr) { printNamedAttribute(attr); });
2022     os << '}';
2023   };
2024 
2025   // If no attributes are elided, we can directly print with no filtering.
2026   if (elidedAttrs.empty())
2027     return printFilteredAttributesFn(attrs);
2028 
2029   // Otherwise, filter out any attributes that shouldn't be included.
2030   llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
2031                                                 elidedAttrs.end());
2032   auto filteredAttrs = llvm::make_filter_range(attrs, [&](NamedAttribute attr) {
2033     return !elidedAttrsSet.contains(attr.first.strref());
2034   });
2035   if (!filteredAttrs.empty())
2036     printFilteredAttributesFn(filteredAttrs);
2037 }
2038 
2039 void AsmPrinter::Impl::printNamedAttribute(NamedAttribute attr) {
2040   if (isBareIdentifier(attr.first)) {
2041     os << attr.first;
2042   } else {
2043     os << '"';
2044     printEscapedString(attr.first.strref(), os);
2045     os << '"';
2046   }
2047 
2048   // Pretty printing elides the attribute value for unit attributes.
2049   if (attr.second.isa<UnitAttr>())
2050     return;
2051 
2052   os << " = ";
2053   printAttribute(attr.second);
2054 }
2055 
2056 void AsmPrinter::Impl::printDialectAttribute(Attribute attr) {
2057   auto &dialect = attr.getDialect();
2058 
2059   // Ask the dialect to serialize the attribute to a string.
2060   std::string attrName;
2061   {
2062     llvm::raw_string_ostream attrNameStr(attrName);
2063     Impl subPrinter(attrNameStr, printerFlags, state);
2064     DialectAsmPrinter printer(subPrinter);
2065     dialect.printAttribute(attr, printer);
2066   }
2067   printDialectSymbol(os, "#", dialect.getNamespace(), attrName);
2068 }
2069 
2070 void AsmPrinter::Impl::printDialectType(Type type) {
2071   auto &dialect = type.getDialect();
2072 
2073   // Ask the dialect to serialize the type to a string.
2074   std::string typeName;
2075   {
2076     llvm::raw_string_ostream typeNameStr(typeName);
2077     Impl subPrinter(typeNameStr, printerFlags, state);
2078     DialectAsmPrinter printer(subPrinter);
2079     dialect.printType(type, printer);
2080   }
2081   printDialectSymbol(os, "!", dialect.getNamespace(), typeName);
2082 }
2083 
2084 //===--------------------------------------------------------------------===//
2085 // AsmPrinter
2086 //===--------------------------------------------------------------------===//
2087 
2088 AsmPrinter::~AsmPrinter() {}
2089 
2090 raw_ostream &AsmPrinter::getStream() const {
2091   assert(impl && "expected AsmPrinter::getStream to be overriden");
2092   return impl->getStream();
2093 }
2094 
2095 /// Print the given floating point value in a stablized form.
2096 void AsmPrinter::printFloat(const APFloat &value) {
2097   assert(impl && "expected AsmPrinter::printFloat to be overriden");
2098   printFloatValue(value, impl->getStream());
2099 }
2100 
2101 void AsmPrinter::printType(Type type) {
2102   assert(impl && "expected AsmPrinter::printType to be overriden");
2103   impl->printType(type);
2104 }
2105 
2106 void AsmPrinter::printAttribute(Attribute attr) {
2107   assert(impl && "expected AsmPrinter::printAttribute to be overriden");
2108   impl->printAttribute(attr);
2109 }
2110 
2111 void AsmPrinter::printAttributeWithoutType(Attribute attr) {
2112   assert(impl &&
2113          "expected AsmPrinter::printAttributeWithoutType to be overriden");
2114   impl->printAttribute(attr, Impl::AttrTypeElision::Must);
2115 }
2116 
2117 void AsmPrinter::printSymbolName(StringRef symbolRef) {
2118   assert(impl && "expected AsmPrinter::printSymbolName to be overriden");
2119   ::printSymbolReference(symbolRef, impl->getStream());
2120 }
2121 
2122 //===----------------------------------------------------------------------===//
2123 // Affine expressions and maps
2124 //===----------------------------------------------------------------------===//
2125 
2126 void AsmPrinter::Impl::printAffineExpr(
2127     AffineExpr expr, function_ref<void(unsigned, bool)> printValueName) {
2128   printAffineExprInternal(expr, BindingStrength::Weak, printValueName);
2129 }
2130 
2131 void AsmPrinter::Impl::printAffineExprInternal(
2132     AffineExpr expr, BindingStrength enclosingTightness,
2133     function_ref<void(unsigned, bool)> printValueName) {
2134   const char *binopSpelling = nullptr;
2135   switch (expr.getKind()) {
2136   case AffineExprKind::SymbolId: {
2137     unsigned pos = expr.cast<AffineSymbolExpr>().getPosition();
2138     if (printValueName)
2139       printValueName(pos, /*isSymbol=*/true);
2140     else
2141       os << 's' << pos;
2142     return;
2143   }
2144   case AffineExprKind::DimId: {
2145     unsigned pos = expr.cast<AffineDimExpr>().getPosition();
2146     if (printValueName)
2147       printValueName(pos, /*isSymbol=*/false);
2148     else
2149       os << 'd' << pos;
2150     return;
2151   }
2152   case AffineExprKind::Constant:
2153     os << expr.cast<AffineConstantExpr>().getValue();
2154     return;
2155   case AffineExprKind::Add:
2156     binopSpelling = " + ";
2157     break;
2158   case AffineExprKind::Mul:
2159     binopSpelling = " * ";
2160     break;
2161   case AffineExprKind::FloorDiv:
2162     binopSpelling = " floordiv ";
2163     break;
2164   case AffineExprKind::CeilDiv:
2165     binopSpelling = " ceildiv ";
2166     break;
2167   case AffineExprKind::Mod:
2168     binopSpelling = " mod ";
2169     break;
2170   }
2171 
2172   auto binOp = expr.cast<AffineBinaryOpExpr>();
2173   AffineExpr lhsExpr = binOp.getLHS();
2174   AffineExpr rhsExpr = binOp.getRHS();
2175 
2176   // Handle tightly binding binary operators.
2177   if (binOp.getKind() != AffineExprKind::Add) {
2178     if (enclosingTightness == BindingStrength::Strong)
2179       os << '(';
2180 
2181     // Pretty print multiplication with -1.
2182     auto rhsConst = rhsExpr.dyn_cast<AffineConstantExpr>();
2183     if (rhsConst && binOp.getKind() == AffineExprKind::Mul &&
2184         rhsConst.getValue() == -1) {
2185       os << "-";
2186       printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
2187       if (enclosingTightness == BindingStrength::Strong)
2188         os << ')';
2189       return;
2190     }
2191 
2192     printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
2193 
2194     os << binopSpelling;
2195     printAffineExprInternal(rhsExpr, BindingStrength::Strong, printValueName);
2196 
2197     if (enclosingTightness == BindingStrength::Strong)
2198       os << ')';
2199     return;
2200   }
2201 
2202   // Print out special "pretty" forms for add.
2203   if (enclosingTightness == BindingStrength::Strong)
2204     os << '(';
2205 
2206   // Pretty print addition to a product that has a negative operand as a
2207   // subtraction.
2208   if (auto rhs = rhsExpr.dyn_cast<AffineBinaryOpExpr>()) {
2209     if (rhs.getKind() == AffineExprKind::Mul) {
2210       AffineExpr rrhsExpr = rhs.getRHS();
2211       if (auto rrhs = rrhsExpr.dyn_cast<AffineConstantExpr>()) {
2212         if (rrhs.getValue() == -1) {
2213           printAffineExprInternal(lhsExpr, BindingStrength::Weak,
2214                                   printValueName);
2215           os << " - ";
2216           if (rhs.getLHS().getKind() == AffineExprKind::Add) {
2217             printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
2218                                     printValueName);
2219           } else {
2220             printAffineExprInternal(rhs.getLHS(), BindingStrength::Weak,
2221                                     printValueName);
2222           }
2223 
2224           if (enclosingTightness == BindingStrength::Strong)
2225             os << ')';
2226           return;
2227         }
2228 
2229         if (rrhs.getValue() < -1) {
2230           printAffineExprInternal(lhsExpr, BindingStrength::Weak,
2231                                   printValueName);
2232           os << " - ";
2233           printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
2234                                   printValueName);
2235           os << " * " << -rrhs.getValue();
2236           if (enclosingTightness == BindingStrength::Strong)
2237             os << ')';
2238           return;
2239         }
2240       }
2241     }
2242   }
2243 
2244   // Pretty print addition to a negative number as a subtraction.
2245   if (auto rhsConst = rhsExpr.dyn_cast<AffineConstantExpr>()) {
2246     if (rhsConst.getValue() < 0) {
2247       printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
2248       os << " - " << -rhsConst.getValue();
2249       if (enclosingTightness == BindingStrength::Strong)
2250         os << ')';
2251       return;
2252     }
2253   }
2254 
2255   printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
2256 
2257   os << " + ";
2258   printAffineExprInternal(rhsExpr, BindingStrength::Weak, printValueName);
2259 
2260   if (enclosingTightness == BindingStrength::Strong)
2261     os << ')';
2262 }
2263 
2264 void AsmPrinter::Impl::printAffineConstraint(AffineExpr expr, bool isEq) {
2265   printAffineExprInternal(expr, BindingStrength::Weak);
2266   isEq ? os << " == 0" : os << " >= 0";
2267 }
2268 
2269 void AsmPrinter::Impl::printAffineMap(AffineMap map) {
2270   // Dimension identifiers.
2271   os << '(';
2272   for (int i = 0; i < (int)map.getNumDims() - 1; ++i)
2273     os << 'd' << i << ", ";
2274   if (map.getNumDims() >= 1)
2275     os << 'd' << map.getNumDims() - 1;
2276   os << ')';
2277 
2278   // Symbolic identifiers.
2279   if (map.getNumSymbols() != 0) {
2280     os << '[';
2281     for (unsigned i = 0; i < map.getNumSymbols() - 1; ++i)
2282       os << 's' << i << ", ";
2283     if (map.getNumSymbols() >= 1)
2284       os << 's' << map.getNumSymbols() - 1;
2285     os << ']';
2286   }
2287 
2288   // Result affine expressions.
2289   os << " -> (";
2290   interleaveComma(map.getResults(),
2291                   [&](AffineExpr expr) { printAffineExpr(expr); });
2292   os << ')';
2293 }
2294 
2295 void AsmPrinter::Impl::printIntegerSet(IntegerSet set) {
2296   // Dimension identifiers.
2297   os << '(';
2298   for (unsigned i = 1; i < set.getNumDims(); ++i)
2299     os << 'd' << i - 1 << ", ";
2300   if (set.getNumDims() >= 1)
2301     os << 'd' << set.getNumDims() - 1;
2302   os << ')';
2303 
2304   // Symbolic identifiers.
2305   if (set.getNumSymbols() != 0) {
2306     os << '[';
2307     for (unsigned i = 0; i < set.getNumSymbols() - 1; ++i)
2308       os << 's' << i << ", ";
2309     if (set.getNumSymbols() >= 1)
2310       os << 's' << set.getNumSymbols() - 1;
2311     os << ']';
2312   }
2313 
2314   // Print constraints.
2315   os << " : (";
2316   int numConstraints = set.getNumConstraints();
2317   for (int i = 1; i < numConstraints; ++i) {
2318     printAffineConstraint(set.getConstraint(i - 1), set.isEq(i - 1));
2319     os << ", ";
2320   }
2321   if (numConstraints >= 1)
2322     printAffineConstraint(set.getConstraint(numConstraints - 1),
2323                           set.isEq(numConstraints - 1));
2324   os << ')';
2325 }
2326 
2327 //===----------------------------------------------------------------------===//
2328 // OperationPrinter
2329 //===----------------------------------------------------------------------===//
2330 
2331 namespace {
2332 /// This class contains the logic for printing operations, regions, and blocks.
2333 class OperationPrinter : public AsmPrinter::Impl, private OpAsmPrinter {
2334 public:
2335   using Impl = AsmPrinter::Impl;
2336   using Impl::printType;
2337 
2338   explicit OperationPrinter(raw_ostream &os, OpPrintingFlags flags,
2339                             AsmStateImpl &state)
2340       : Impl(os, flags, &state), OpAsmPrinter(static_cast<Impl &>(*this)) {}
2341 
2342   /// Print the given top-level operation.
2343   void printTopLevelOperation(Operation *op);
2344 
2345   /// Print the given operation with its indent and location.
2346   void print(Operation *op);
2347   /// Print the bare location, not including indentation/location/etc.
2348   void printOperation(Operation *op);
2349   /// Print the given operation in the generic form.
2350   void printGenericOp(Operation *op, bool printOpName) override;
2351 
2352   /// Print the name of the given block.
2353   void printBlockName(Block *block);
2354 
2355   /// Print the given block. If 'printBlockArgs' is false, the arguments of the
2356   /// block are not printed. If 'printBlockTerminator' is false, the terminator
2357   /// operation of the block is not printed.
2358   void print(Block *block, bool printBlockArgs = true,
2359              bool printBlockTerminator = true);
2360 
2361   /// Print the ID of the given value, optionally with its result number.
2362   void printValueID(Value value, bool printResultNo = true,
2363                     raw_ostream *streamOverride = nullptr) const;
2364 
2365   //===--------------------------------------------------------------------===//
2366   // OpAsmPrinter methods
2367   //===--------------------------------------------------------------------===//
2368 
2369   /// Print a newline and indent the printer to the start of the current
2370   /// operation.
2371   void printNewline() override {
2372     os << newLine;
2373     os.indent(currentIndent);
2374   }
2375 
2376   /// Print a block argument in the usual format of:
2377   ///   %ssaName : type {attr1=42} loc("here")
2378   /// where location printing is controlled by the standard internal option.
2379   /// You may pass omitType=true to not print a type, and pass an empty
2380   /// attribute list if you don't care for attributes.
2381   void printRegionArgument(BlockArgument arg,
2382                            ArrayRef<NamedAttribute> argAttrs = {},
2383                            bool omitType = false) override;
2384 
2385   /// Print the ID for the given value.
2386   void printOperand(Value value) override { printValueID(value); }
2387   void printOperand(Value value, raw_ostream &os) override {
2388     printValueID(value, /*printResultNo=*/true, &os);
2389   }
2390 
2391   /// Print an optional attribute dictionary with a given set of elided values.
2392   void printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
2393                              ArrayRef<StringRef> elidedAttrs = {}) override {
2394     Impl::printOptionalAttrDict(attrs, elidedAttrs);
2395   }
2396   void printOptionalAttrDictWithKeyword(
2397       ArrayRef<NamedAttribute> attrs,
2398       ArrayRef<StringRef> elidedAttrs = {}) override {
2399     Impl::printOptionalAttrDict(attrs, elidedAttrs,
2400                                 /*withKeyword=*/true);
2401   }
2402 
2403   /// Print the given successor.
2404   void printSuccessor(Block *successor) override;
2405 
2406   /// Print an operation successor with the operands used for the block
2407   /// arguments.
2408   void printSuccessorAndUseList(Block *successor,
2409                                 ValueRange succOperands) override;
2410 
2411   /// Print the given region.
2412   void printRegion(Region &region, bool printEntryBlockArgs,
2413                    bool printBlockTerminators, bool printEmptyBlock) override;
2414 
2415   /// Renumber the arguments for the specified region to the same names as the
2416   /// SSA values in namesToUse. This may only be used for IsolatedFromAbove
2417   /// operations. If any entry in namesToUse is null, the corresponding
2418   /// argument name is left alone.
2419   void shadowRegionArgs(Region &region, ValueRange namesToUse) override {
2420     state->getSSANameState().shadowRegionArgs(region, namesToUse);
2421   }
2422 
2423   /// Print the given affine map with the symbol and dimension operands printed
2424   /// inline with the map.
2425   void printAffineMapOfSSAIds(AffineMapAttr mapAttr,
2426                               ValueRange operands) override;
2427 
2428   /// Print the given affine expression with the symbol and dimension operands
2429   /// printed inline with the expression.
2430   void printAffineExprOfSSAIds(AffineExpr expr, ValueRange dimOperands,
2431                                ValueRange symOperands) override;
2432 
2433 private:
2434   // Contains the stack of default dialects to use when printing regions.
2435   // A new dialect is pushed to the stack before parsing regions nested under an
2436   // operation implementing `OpAsmOpInterface`, and popped when done. At the
2437   // top-level we start with "builtin" as the default, so that the top-level
2438   // `module` operation prints as-is.
2439   SmallVector<StringRef> defaultDialectStack{"builtin"};
2440 
2441   /// The number of spaces used for indenting nested operations.
2442   const static unsigned indentWidth = 2;
2443 
2444   // This is the current indentation level for nested structures.
2445   unsigned currentIndent = 0;
2446 };
2447 } // end anonymous namespace
2448 
2449 void OperationPrinter::printTopLevelOperation(Operation *op) {
2450   // Output the aliases at the top level that can't be deferred.
2451   state->getAliasState().printNonDeferredAliases(os, newLine);
2452 
2453   // Print the module.
2454   print(op);
2455   os << newLine;
2456 
2457   // Output the aliases at the top level that can be deferred.
2458   state->getAliasState().printDeferredAliases(os, newLine);
2459 }
2460 
2461 /// Print a block argument in the usual format of:
2462 ///   %ssaName : type {attr1=42} loc("here")
2463 /// where location printing is controlled by the standard internal option.
2464 /// You may pass omitType=true to not print a type, and pass an empty
2465 /// attribute list if you don't care for attributes.
2466 void OperationPrinter::printRegionArgument(BlockArgument arg,
2467                                            ArrayRef<NamedAttribute> argAttrs,
2468                                            bool omitType) {
2469   printOperand(arg);
2470   if (!omitType) {
2471     os << ": ";
2472     printType(arg.getType());
2473   }
2474   printOptionalAttrDict(argAttrs);
2475   // TODO: We should allow location aliases on block arguments.
2476   printTrailingLocation(arg.getLoc(), /*allowAlias*/ false);
2477 }
2478 
2479 void OperationPrinter::print(Operation *op) {
2480   // Track the location of this operation.
2481   state->registerOperationLocation(op, newLine.curLine, currentIndent);
2482 
2483   os.indent(currentIndent);
2484   printOperation(op);
2485   printTrailingLocation(op->getLoc());
2486 }
2487 
2488 void OperationPrinter::printOperation(Operation *op) {
2489   if (size_t numResults = op->getNumResults()) {
2490     auto printResultGroup = [&](size_t resultNo, size_t resultCount) {
2491       printValueID(op->getResult(resultNo), /*printResultNo=*/false);
2492       if (resultCount > 1)
2493         os << ':' << resultCount;
2494     };
2495 
2496     // Check to see if this operation has multiple result groups.
2497     ArrayRef<int> resultGroups = state->getSSANameState().getOpResultGroups(op);
2498     if (!resultGroups.empty()) {
2499       // Interleave the groups excluding the last one, this one will be handled
2500       // separately.
2501       interleaveComma(llvm::seq<int>(0, resultGroups.size() - 1), [&](int i) {
2502         printResultGroup(resultGroups[i],
2503                          resultGroups[i + 1] - resultGroups[i]);
2504       });
2505       os << ", ";
2506       printResultGroup(resultGroups.back(), numResults - resultGroups.back());
2507 
2508     } else {
2509       printResultGroup(/*resultNo=*/0, /*resultCount=*/numResults);
2510     }
2511 
2512     os << " = ";
2513   }
2514 
2515   // If requested, always print the generic form.
2516   if (!printerFlags.shouldPrintGenericOpForm()) {
2517     // Check to see if this is a known operation.  If so, use the registered
2518     // custom printer hook.
2519     if (auto *opInfo = op->getAbstractOperation()) {
2520       opInfo->printAssembly(op, *this, defaultDialectStack.back());
2521       return;
2522     }
2523     // Otherwise try to dispatch to the dialect, if available.
2524     if (Dialect *dialect = op->getDialect()) {
2525       if (auto opPrinter = dialect->getOperationPrinter(op)) {
2526         // Print the op name first.
2527         StringRef name = op->getName().getStringRef();
2528         name.consume_front((defaultDialectStack.back() + ".").str());
2529         printEscapedString(name, os);
2530         // Print the rest of the op now.
2531         opPrinter(op, *this);
2532         return;
2533       }
2534     }
2535   }
2536 
2537   // Otherwise print with the generic assembly form.
2538   printGenericOp(op, /*printOpName=*/true);
2539 }
2540 
2541 void OperationPrinter::printGenericOp(Operation *op, bool printOpName) {
2542   if (printOpName) {
2543     os << '"';
2544     printEscapedString(op->getName().getStringRef(), os);
2545     os << '"';
2546   }
2547   os << '(';
2548   interleaveComma(op->getOperands(), [&](Value value) { printValueID(value); });
2549   os << ')';
2550 
2551   // For terminators, print the list of successors and their operands.
2552   if (op->getNumSuccessors() != 0) {
2553     os << '[';
2554     interleaveComma(op->getSuccessors(),
2555                     [&](Block *successor) { printBlockName(successor); });
2556     os << ']';
2557   }
2558 
2559   // Print regions.
2560   if (op->getNumRegions() != 0) {
2561     os << " (";
2562     interleaveComma(op->getRegions(), [&](Region &region) {
2563       printRegion(region, /*printEntryBlockArgs=*/true,
2564                   /*printBlockTerminators=*/true, /*printEmptyBlock=*/true);
2565     });
2566     os << ')';
2567   }
2568 
2569   auto attrs = op->getAttrs();
2570   printOptionalAttrDict(attrs);
2571 
2572   // Print the type signature of the operation.
2573   os << " : ";
2574   printFunctionalType(op);
2575 }
2576 
2577 void OperationPrinter::printBlockName(Block *block) {
2578   auto id = state->getSSANameState().getBlockID(block);
2579   if (id != SSANameState::NameSentinel)
2580     os << "^bb" << id;
2581   else
2582     os << "^INVALIDBLOCK";
2583 }
2584 
2585 void OperationPrinter::print(Block *block, bool printBlockArgs,
2586                              bool printBlockTerminator) {
2587   // Print the block label and argument list if requested.
2588   if (printBlockArgs) {
2589     os.indent(currentIndent);
2590     printBlockName(block);
2591 
2592     // Print the argument list if non-empty.
2593     if (!block->args_empty()) {
2594       os << '(';
2595       interleaveComma(block->getArguments(), [&](BlockArgument arg) {
2596         printValueID(arg);
2597         os << ": ";
2598         printType(arg.getType());
2599         // TODO: We should allow location aliases on block arguments.
2600         printTrailingLocation(arg.getLoc(), /*allowAlias*/ false);
2601       });
2602       os << ')';
2603     }
2604     os << ':';
2605 
2606     // Print out some context information about the predecessors of this block.
2607     if (!block->getParent()) {
2608       os << "  // block is not in a region!";
2609     } else if (block->hasNoPredecessors()) {
2610       os << "  // no predecessors";
2611     } else if (auto *pred = block->getSinglePredecessor()) {
2612       os << "  // pred: ";
2613       printBlockName(pred);
2614     } else {
2615       // We want to print the predecessors in increasing numeric order, not in
2616       // whatever order the use-list is in, so gather and sort them.
2617       SmallVector<std::pair<unsigned, Block *>, 4> predIDs;
2618       for (auto *pred : block->getPredecessors())
2619         predIDs.push_back({state->getSSANameState().getBlockID(pred), pred});
2620       llvm::array_pod_sort(predIDs.begin(), predIDs.end());
2621 
2622       os << "  // " << predIDs.size() << " preds: ";
2623 
2624       interleaveComma(predIDs, [&](std::pair<unsigned, Block *> pred) {
2625         printBlockName(pred.second);
2626       });
2627     }
2628     os << newLine;
2629   }
2630 
2631   currentIndent += indentWidth;
2632   bool hasTerminator =
2633       !block->empty() && block->back().hasTrait<OpTrait::IsTerminator>();
2634   auto range = llvm::make_range(
2635       block->begin(),
2636       std::prev(block->end(),
2637                 (!hasTerminator || printBlockTerminator) ? 0 : 1));
2638   for (auto &op : range) {
2639     print(&op);
2640     os << newLine;
2641   }
2642   currentIndent -= indentWidth;
2643 }
2644 
2645 void OperationPrinter::printValueID(Value value, bool printResultNo,
2646                                     raw_ostream *streamOverride) const {
2647   state->getSSANameState().printValueID(value, printResultNo,
2648                                         streamOverride ? *streamOverride : os);
2649 }
2650 
2651 void OperationPrinter::printSuccessor(Block *successor) {
2652   printBlockName(successor);
2653 }
2654 
2655 void OperationPrinter::printSuccessorAndUseList(Block *successor,
2656                                                 ValueRange succOperands) {
2657   printBlockName(successor);
2658   if (succOperands.empty())
2659     return;
2660 
2661   os << '(';
2662   interleaveComma(succOperands,
2663                   [this](Value operand) { printValueID(operand); });
2664   os << " : ";
2665   interleaveComma(succOperands,
2666                   [this](Value operand) { printType(operand.getType()); });
2667   os << ')';
2668 }
2669 
2670 void OperationPrinter::printRegion(Region &region, bool printEntryBlockArgs,
2671                                    bool printBlockTerminators,
2672                                    bool printEmptyBlock) {
2673   os << " {" << newLine;
2674   if (!region.empty()) {
2675     auto restoreDefaultDialect =
2676         llvm::make_scope_exit([&]() { defaultDialectStack.pop_back(); });
2677     if (auto iface = dyn_cast<OpAsmOpInterface>(region.getParentOp()))
2678       defaultDialectStack.push_back(iface.getDefaultDialect());
2679     else
2680       defaultDialectStack.push_back("");
2681 
2682     auto *entryBlock = &region.front();
2683     // Force printing the block header if printEmptyBlock is set and the block
2684     // is empty or if printEntryBlockArgs is set and there are arguments to
2685     // print.
2686     bool shouldAlwaysPrintBlockHeader =
2687         (printEmptyBlock && entryBlock->empty()) ||
2688         (printEntryBlockArgs && entryBlock->getNumArguments() != 0);
2689     print(entryBlock, shouldAlwaysPrintBlockHeader, printBlockTerminators);
2690     for (auto &b : llvm::drop_begin(region.getBlocks(), 1))
2691       print(&b);
2692   }
2693   os.indent(currentIndent) << "}";
2694 }
2695 
2696 void OperationPrinter::printAffineMapOfSSAIds(AffineMapAttr mapAttr,
2697                                               ValueRange operands) {
2698   AffineMap map = mapAttr.getValue();
2699   unsigned numDims = map.getNumDims();
2700   auto printValueName = [&](unsigned pos, bool isSymbol) {
2701     unsigned index = isSymbol ? numDims + pos : pos;
2702     assert(index < operands.size());
2703     if (isSymbol)
2704       os << "symbol(";
2705     printValueID(operands[index]);
2706     if (isSymbol)
2707       os << ')';
2708   };
2709 
2710   interleaveComma(map.getResults(), [&](AffineExpr expr) {
2711     printAffineExpr(expr, printValueName);
2712   });
2713 }
2714 
2715 void OperationPrinter::printAffineExprOfSSAIds(AffineExpr expr,
2716                                                ValueRange dimOperands,
2717                                                ValueRange symOperands) {
2718   auto printValueName = [&](unsigned pos, bool isSymbol) {
2719     if (!isSymbol)
2720       return printValueID(dimOperands[pos]);
2721     os << "symbol(";
2722     printValueID(symOperands[pos]);
2723     os << ')';
2724   };
2725   printAffineExpr(expr, printValueName);
2726 }
2727 
2728 //===----------------------------------------------------------------------===//
2729 // print and dump methods
2730 //===----------------------------------------------------------------------===//
2731 
2732 void Attribute::print(raw_ostream &os) const {
2733   AsmPrinter::Impl(os).printAttribute(*this);
2734 }
2735 
2736 void Attribute::dump() const {
2737   print(llvm::errs());
2738   llvm::errs() << "\n";
2739 }
2740 
2741 void Type::print(raw_ostream &os) const {
2742   AsmPrinter::Impl(os).printType(*this);
2743 }
2744 
2745 void Type::dump() const { print(llvm::errs()); }
2746 
2747 void AffineMap::dump() const {
2748   print(llvm::errs());
2749   llvm::errs() << "\n";
2750 }
2751 
2752 void IntegerSet::dump() const {
2753   print(llvm::errs());
2754   llvm::errs() << "\n";
2755 }
2756 
2757 void AffineExpr::print(raw_ostream &os) const {
2758   if (!expr) {
2759     os << "<<NULL AFFINE EXPR>>";
2760     return;
2761   }
2762   AsmPrinter::Impl(os).printAffineExpr(*this);
2763 }
2764 
2765 void AffineExpr::dump() const {
2766   print(llvm::errs());
2767   llvm::errs() << "\n";
2768 }
2769 
2770 void AffineMap::print(raw_ostream &os) const {
2771   if (!map) {
2772     os << "<<NULL AFFINE MAP>>";
2773     return;
2774   }
2775   AsmPrinter::Impl(os).printAffineMap(*this);
2776 }
2777 
2778 void IntegerSet::print(raw_ostream &os) const {
2779   AsmPrinter::Impl(os).printIntegerSet(*this);
2780 }
2781 
2782 void Value::print(raw_ostream &os) {
2783   if (auto *op = getDefiningOp())
2784     return op->print(os);
2785   // TODO: Improve BlockArgument print'ing.
2786   BlockArgument arg = this->cast<BlockArgument>();
2787   os << "<block argument> of type '" << arg.getType()
2788      << "' at index: " << arg.getArgNumber();
2789 }
2790 void Value::print(raw_ostream &os, AsmState &state) {
2791   if (auto *op = getDefiningOp())
2792     return op->print(os, state);
2793 
2794   // TODO: Improve BlockArgument print'ing.
2795   BlockArgument arg = this->cast<BlockArgument>();
2796   os << "<block argument> of type '" << arg.getType()
2797      << "' at index: " << arg.getArgNumber();
2798 }
2799 
2800 void Value::dump() {
2801   print(llvm::errs());
2802   llvm::errs() << "\n";
2803 }
2804 
2805 void Value::printAsOperand(raw_ostream &os, AsmState &state) {
2806   // TODO: This doesn't necessarily capture all potential cases.
2807   // Currently, region arguments can be shadowed when printing the main
2808   // operation. If the IR hasn't been printed, this will produce the old SSA
2809   // name and not the shadowed name.
2810   state.getImpl().getSSANameState().printValueID(*this, /*printResultNo=*/true,
2811                                                  os);
2812 }
2813 
2814 void Operation::print(raw_ostream &os, const OpPrintingFlags &printerFlags) {
2815   // If this is a top level operation, we also print aliases.
2816   if (!getParent() && !printerFlags.shouldUseLocalScope()) {
2817     AsmState state(this, printerFlags);
2818     state.getImpl().initializeAliases(this);
2819     print(os, state, printerFlags);
2820     return;
2821   }
2822 
2823   // Find the operation to number from based upon the provided flags.
2824   Operation *op = this;
2825   bool shouldUseLocalScope = printerFlags.shouldUseLocalScope();
2826   do {
2827     // If we are printing local scope, stop at the first operation that is
2828     // isolated from above.
2829     if (shouldUseLocalScope && op->hasTrait<OpTrait::IsIsolatedFromAbove>())
2830       break;
2831 
2832     // Otherwise, traverse up to the next parent.
2833     Operation *parentOp = op->getParentOp();
2834     if (!parentOp)
2835       break;
2836     op = parentOp;
2837   } while (true);
2838 
2839   AsmState state(op, printerFlags);
2840   print(os, state, printerFlags);
2841 }
2842 void Operation::print(raw_ostream &os, AsmState &state,
2843                       const OpPrintingFlags &flags) {
2844   OperationPrinter printer(os, flags, state.getImpl());
2845   if (!getParent() && !flags.shouldUseLocalScope())
2846     printer.printTopLevelOperation(this);
2847   else
2848     printer.print(this);
2849 }
2850 
2851 void Operation::dump() {
2852   print(llvm::errs(), OpPrintingFlags().useLocalScope());
2853   llvm::errs() << "\n";
2854 }
2855 
2856 void Block::print(raw_ostream &os) {
2857   Operation *parentOp = getParentOp();
2858   if (!parentOp) {
2859     os << "<<UNLINKED BLOCK>>\n";
2860     return;
2861   }
2862   // Get the top-level op.
2863   while (auto *nextOp = parentOp->getParentOp())
2864     parentOp = nextOp;
2865 
2866   AsmState state(parentOp);
2867   print(os, state);
2868 }
2869 void Block::print(raw_ostream &os, AsmState &state) {
2870   OperationPrinter(os, /*flags=*/llvm::None, state.getImpl()).print(this);
2871 }
2872 
2873 void Block::dump() { print(llvm::errs()); }
2874 
2875 /// Print out the name of the block without printing its body.
2876 void Block::printAsOperand(raw_ostream &os, bool printType) {
2877   Operation *parentOp = getParentOp();
2878   if (!parentOp) {
2879     os << "<<UNLINKED BLOCK>>\n";
2880     return;
2881   }
2882   AsmState state(parentOp);
2883   printAsOperand(os, state);
2884 }
2885 void Block::printAsOperand(raw_ostream &os, AsmState &state) {
2886   OperationPrinter printer(os, /*flags=*/llvm::None, state.getImpl());
2887   printer.printBlockName(this);
2888 }
2889