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