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