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