MLIR: lib/IR/AsmPrinter.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
31 #include "llvm/ADT/APFloat.h"
32 #include "llvm/ADT/ArrayRef.h"
33 #include "llvm/ADT/DenseMap.h"
34 #include "llvm/ADT/MapVector.h"
35 #include "llvm/ADT/STLExtras.h"
36 #include "llvm/ADT/ScopeExit.h"
37 #include "llvm/ADT/ScopedHashTable.h"
38 #include "llvm/ADT/SetVector.h"
39 #include "llvm/ADT/SmallString.h"
40 #include "llvm/ADT/StringExtras.h"
41 #include "llvm/ADT/StringSet.h"
42 #include "llvm/ADT/TypeSwitch.h"
43 #include "llvm/Support/CommandLine.h"
44 #include "llvm/Support/Debug.h"
45 #include "llvm/Support/Endian.h"
46 #include "llvm/Support/ManagedStatic.h"
47 #include "llvm/Support/Regex.h"
48 #include "llvm/Support/SaveAndRestore.h"
49 #include "llvm/Support/Threading.h"
50 #include "llvm/Support/raw_ostream.h"
51 #include <type_traits>
52
53 #include
54 #include
55
56 using namespace mlir;
58
59 #define DEBUG_TYPE "mlir-asm-printer"
60
62
64
65
66
67
68
72
74
75
76
77
80 [&]() { return parseType(result.emplace_back()); });
81 }
82
83
84
85
86
88
89
90
91
92
94
96 auto &os = getStream();
97 os << '(';
98 llvm::interleaveComma(op->getOperands(), os, [&](Value operand) {
99
100 *this << (operand ? operand.getType() : Type());
101 });
102 os << ") -> ";
103
104
105
109 wrapped = true;
110
111 if (wrapped)
112 os << '(';
113
114 llvm::interleaveComma(op->getResults(), os, [&](const OpResult &result) {
115
116 *this << (result ? result.getType() : Type());
117 });
118
119 if (wrapped)
120 os << ')';
121 }
122
123
124
125
126
127
128 #include "mlir/IR/OpAsmAttrInterface.cpp.inc"
129 #include "mlir/IR/OpAsmOpInterface.cpp.inc"
130 #include "mlir/IR/OpAsmTypeInterface.cpp.inc"
131
132 LogicalResult
134 return entry.emitError() << "unknown 'resource' key '" << entry.getKey()
135 << "' for dialect '" << getDialect()->getNamespace()
136 << "'";
137 }
138
139
140
141
142
143 namespace {
144
145
146
147 struct AsmPrinterOptions {
148 llvm:🆑:opt<int64_t> printElementsAttrWithHexIfLarger{
149 "mlir-print-elementsattrs-with-hex-if-larger",
150 llvm:🆑:desc(
151 "Print DenseElementsAttrs with a hex string that have "
152 "more elements than the given upper limit (use -1 to disable)")};
153
154 llvm:🆑:opt elideElementsAttrIfLarger{
155 "mlir-elide-elementsattrs-if-larger",
156 llvm:🆑:desc("Elide ElementsAttrs with \"...\" that have "
157 "more elements than the given upper limit")};
158
159 llvm:🆑:opt elideResourceStringsIfLarger{
160 "mlir-elide-resource-strings-if-larger",
161 llvm:🆑:desc(
162 "Elide printing value of resources if string is too long in chars.")};
163
164 llvm:🆑:opt printDebugInfoOpt{
165 "mlir-print-debuginfo", llvm:🆑:init(false),
166 llvm:🆑:desc("Print debug info in MLIR output")};
167
168 llvm:🆑:opt printPrettyDebugInfoOpt{
169 "mlir-pretty-debuginfo", llvm:🆑:init(false),
170 llvm:🆑:desc("Print pretty debug info in MLIR output")};
171
172
173
174 llvm:🆑:opt printGenericOpFormOpt{
175 "mlir-print-op-generic", llvm:🆑:init(false),
176 llvm:🆑:desc("Print the generic op form"), llvm:🆑:Hidden};
177
178 llvm:🆑:opt assumeVerifiedOpt{
179 "mlir-print-assume-verified", llvm:🆑:init(false),
180 llvm:🆑:desc("Skip op verification when using custom printers"),
181 llvm:🆑:Hidden};
182
183 llvm:🆑:opt printLocalScopeOpt{
184 "mlir-print-local-scope", llvm:🆑:init(false),
185 llvm:🆑:desc("Print with local scope and inline information (eliding "
186 "aliases for attributes, types, and locations)")};
187
188 llvm:🆑:opt skipRegionsOpt{
189 "mlir-print-skip-regions", llvm:🆑:init(false),
190 llvm:🆑:desc("Skip regions when printing ops.")};
191
192 llvm:🆑:opt printValueUsers{
193 "mlir-print-value-users", llvm:🆑:init(false),
194 llvm:🆑:desc(
195 "Print users of operation results and block arguments as a comment")};
196
197 llvm:🆑:opt printUniqueSSAIDs{
198 "mlir-print-unique-ssa-ids", llvm:🆑:init(false),
199 llvm:🆑:desc("Print unique SSA ID numbers for values, block arguments "
200 "and naming conflicts across all regions")};
201
202 llvm:🆑:opt useNameLocAsPrefix{
203 "mlir-use-nameloc-as-prefix", llvm:🆑:init(false),
204 llvm:🆑:desc("Print SSA IDs using NameLocs as prefixes")};
205 };
206 }
207
208 static llvm::ManagedStatic clOptions;
209
210
211
213
215 }
216
217
219 : printDebugInfoFlag(false), printDebugInfoPrettyFormFlag(false),
220 printGenericOpFormFlag(false), skipRegionsFlag(false),
221 assumeVerifiedFlag(false), printLocalScope(false),
222 printValueUsersFlag(false), printUniqueSSAIDsFlag(false),
223 useNameLocAsPrefix(false) {
224
226 return;
227 if (clOptions->elideElementsAttrIfLarger.getNumOccurrences())
228 elementsAttrElementLimit = clOptions->elideElementsAttrIfLarger;
229 if (clOptions->printElementsAttrWithHexIfLarger.getNumOccurrences())
230 elementsAttrHexElementLimit =
231 clOptions->printElementsAttrWithHexIfLarger.getValue();
232 if (clOptions->elideResourceStringsIfLarger.getNumOccurrences())
233 resourceStringCharLimit = clOptions->elideResourceStringsIfLarger;
234 printDebugInfoFlag = clOptions->printDebugInfoOpt;
235 printDebugInfoPrettyFormFlag = clOptions->printPrettyDebugInfoOpt;
236 printGenericOpFormFlag = clOptions->printGenericOpFormOpt;
237 assumeVerifiedFlag = clOptions->assumeVerifiedOpt;
238 printLocalScope = clOptions->printLocalScopeOpt;
239 skipRegionsFlag = clOptions->skipRegionsOpt;
240 printValueUsersFlag = clOptions->printValueUsers;
241 printUniqueSSAIDsFlag = clOptions->printUniqueSSAIDs;
242 useNameLocAsPrefix = clOptions->useNameLocAsPrefix;
243 }
244
245
246
247
248
251 elementsAttrElementLimit = largeElementLimit;
252 return *this;
253 }
254
257 elementsAttrHexElementLimit = largeElementLimit;
258 return *this;
259 }
260
263 resourceStringCharLimit = largeResourceLimit;
264 return *this;
265 }
266
267
268
270 bool prettyForm) {
271 printDebugInfoFlag = enable;
272 printDebugInfoPrettyFormFlag = prettyForm;
273 return *this;
274 }
275
276
278 printGenericOpFormFlag = enable;
279 return *this;
280 }
281
282
284 skipRegionsFlag = skip;
285 return *this;
286 }
287
288
290 assumeVerifiedFlag = enable;
291 return *this;
292 }
293
294
295
296
298 printLocalScope = enable;
299 return *this;
300 }
301
302
304 printValueUsersFlag = enable;
305 return *this;
306 }
307
308
309
311 printUniqueSSAIDsFlag = enable;
312 return *this;
313 }
314
315
317 return elementsAttrElementLimit &&
318 *elementsAttrElementLimit < int64_t(attr.getNumElements()) &&
319 !llvm::isa(attr);
320 }
321
322
324
325 return (elementsAttrHexElementLimit != -1) &&
326 (elementsAttrHexElementLimit < int64_t(attr.getNumElements())) &&
327 !llvm::isa(attr);
328 }
329
331 useNameLocAsPrefix = enable;
332 return *this;
333 }
334
335
337 return elementsAttrElementLimit;
338 }
339
340
342 return elementsAttrHexElementLimit;
343 }
344
345
347 return resourceStringCharLimit;
348 }
349
350
352 return printDebugInfoFlag;
353 }
354
355
357 return printDebugInfoPrettyFormFlag;
358 }
359
360
362 return printGenericOpFormFlag;
363 }
364
365
367
368
370 return assumeVerifiedFlag;
371 }
372
373
375
376
378 return printValueUsersFlag;
379 }
380
381
384 }
385
386
388 return useNameLocAsPrefix;
389 }
390
391
392
393
394
395 namespace {
396
397
398
399 struct NewLineCounter {
400 unsigned curLine = 1;
401 };
402
403 static raw_ostream &operator<<(raw_ostream &os, NewLineCounter &newLine) {
404 ++newLine.curLine;
405 return os << '\n';
406 }
407 }
408
409
410
411
412
413 namespace mlir {
415 public:
418
419
421
422 template <typename Container, typename UnaryFunctor>
423 inline void interleaveComma(const Container &c, UnaryFunctor eachFn) const {
424 llvm::interleaveComma(c, os, eachFn);
425 }
426
427
428
430
432
433
435
437 };
438
439
442
445
446
447
449
450
452
454
455
456
458
459
460
462
463
464
466
468 void
470 function_ref<void(unsigned, bool)> printValueName = nullptr);
473
475
477
479
480 protected:
483 bool withKeyword = false);
487 bool isTopLevel = false);
488
489
490
492
493
495
496
497
499 bool allowHex);
500
501
503
506
507
509
510
513
514
515
516
518 Weak,
519 Strong,
520 };
523 function_ref<void(unsigned, bool)> printValueName = nullptr);
524
525
527
528
530
531
533
534
536 };
537 }
538
539
540
541
542
543 namespace {
544
545 class SymbolAlias {
546 public:
547 SymbolAlias(StringRef name, uint32_t suffixIndex, bool isType,
548 bool isDeferrable)
549 : name(name), suffixIndex(suffixIndex), isType(isType),
550 isDeferrable(isDeferrable) {}
551
552
553 void print(raw_ostream &os) const {
554 os << (isType ? "!" : "#") << name;
555 if (suffixIndex) {
556 if (isdigit(name.back()))
557 os << '_';
558 os << suffixIndex;
559 }
560 }
561
562
563 bool isTypeAlias() const { return isType; }
564
565
566 bool canBeDeferred() const { return isDeferrable; }
567
568 private:
569
570 StringRef name;
571
572 uint32_t suffixIndex : 30;
573
574 bool isType : 1;
575
576 bool isDeferrable : 1;
577
578 public:
579
580 bool isPrinted = false;
581 };
582
583
584
585
586 class AliasInitializer {
587 public:
588 AliasInitializer(
590 llvm::BumpPtrAllocator &aliasAllocator)
591 : interfaces(interfaces), aliasAllocator(aliasAllocator),
592 aliasOS(aliasBuffer) {}
593
595 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias);
596
597
598
599
600
601
602
603 std::pair<size_t, size_t> visit(Attribute attr, bool canBeDeferred = false,
604 bool elideType = false) {
605 return visitImpl(attr, aliases, canBeDeferred, elideType);
606 }
607
608
609
610
611
612 std::pair<size_t, size_t> visit(Type type, bool canBeDeferred = false) {
613 return visitImpl(type, aliases, canBeDeferred);
614 }
615
616 private:
617 struct InProgressAliasInfo {
618 InProgressAliasInfo()
619 : aliasDepth(0), isType(false), canBeDeferred(false) {}
620 InProgressAliasInfo(StringRef alias)
621 : alias(alias), aliasDepth(1), isType(false), canBeDeferred(false) {}
622
623 bool operator<(const InProgressAliasInfo &rhs) const {
624
625 if (aliasDepth != rhs.aliasDepth)
626 return aliasDepth < rhs.aliasDepth;
627 if (isType != rhs.isType)
628 return isType;
629 return alias < rhs.alias;
630 }
631
632
633
634 std::optional alias;
635
636
637 unsigned aliasDepth : 30;
638
639 bool isType : 1;
640
641 bool canBeDeferred : 1;
642
644 };
645
646
647
648
649
650
651 template <typename T, typename... PrintArgs>
652 std::pair<size_t, size_t>
653 visitImpl(T value,
654 llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
655 bool canBeDeferred, PrintArgs &&...printArgs);
656
657
658 void markAliasNonDeferrable(size_t aliasIndex);
659
660
661
662 template
663 void generateAlias(T symbol, InProgressAliasInfo &alias, bool canBeDeferred);
664
665
666
667 static unsigned
668 uniqueAliasNameIndex(StringRef alias, llvm::StringMap &nameCounts,
670
671
672
673 static void initializeAliases(
674 llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
675 llvm::MapVector<const void *, SymbolAlias> &symbolToAlias);
676
677
679
680
681 llvm::BumpPtrAllocator &aliasAllocator;
682
683
684 llvm::MapVector<const void *, InProgressAliasInfo> aliases;
685
686
688 llvm::raw_svector_ostream aliasOS;
689 };
690
691
692
693
694
695
696 class DummyAliasOperationPrinter : private OpAsmPrinter {
697 public:
698 explicit DummyAliasOperationPrinter(const OpPrintingFlags &printerFlags,
699 AliasInitializer &initializer)
700 : printerFlags(printerFlags), initializer(initializer) {}
701
702
703
704 void printCustomOrGenericOp(Operation *op) override {
705
706 if (printerFlags.shouldPrintDebugInfo())
707 initializer.visit(op->getLoc(), true);
708
709
710 if (!printerFlags.shouldPrintGenericOpForm()) {
712 return;
713 }
714
715
716 printGenericOp(op);
717 }
718
719 private:
720
721 void printGenericOp(Operation *op, bool printOpName = true) override {
722
723 if (!printerFlags.shouldSkipRegions()) {
725 printRegion(region, true,
726 true);
727 }
728
729
734
735
737 printAttribute(attr.getValue());
738 }
739
740
741
742
743 void print(Block *block, bool printBlockArgs = true,
744 bool printBlockTerminator = true) {
745
746
747 if (printBlockArgs) {
750
751
752 if (printerFlags.shouldPrintDebugInfo())
753
754 initializer.visit(arg.getLoc(), false);
755 }
756 }
757
758
759
760 bool hasTerminator =
762 auto range = llvm::make_range(
764 std::prev(block->end(),
765 (!hasTerminator || printBlockTerminator) ? 0 : 1));
767 printCustomOrGenericOp(&op);
768 }
769
770
772 bool printBlockTerminators,
773 bool printEmptyBlock = false) override {
774 if (region.empty())
775 return;
776 if (printerFlags.shouldSkipRegions()) {
777 os << "{...}";
778 return;
779 }
780
781 auto *entryBlock = ®ion.front();
782 print(entryBlock, printEntryBlockArgs, printBlockTerminators);
783 for (Block &b : llvm::drop_begin(region, 1))
785 }
786
788 bool omitType) override {
790
791 if (printerFlags.shouldPrintDebugInfo())
792
793 initializer.visit(arg.getLoc(), false);
794 }
795
796
797 void printType(Type type) override { initializer.visit(type); }
798
799
800 void printAttribute(Attribute attr) override { initializer.visit(attr); }
801 void printAttributeWithoutType(Attribute attr) override {
802 printAttribute(attr);
803 }
804 LogicalResult printAlias(Attribute attr) override {
805 initializer.visit(attr);
806 return success();
807 }
808 LogicalResult printAlias(Type type) override {
809 initializer.visit(type);
810 return success();
811 }
812
813
814 void printOptionalLocationSpecifier(Location loc) override {
815 printAttribute(loc);
816 }
817
818
819
822 if (attrs.empty())
823 return;
824 if (elidedAttrs.empty()) {
826 printAttribute(attr.getValue());
827 return;
828 }
829 llvm::SmallDenseSet elidedAttrsSet(elidedAttrs.begin(),
830 elidedAttrs.end());
832 if (!elidedAttrsSet.contains(attr.getName().strref()))
833 printAttribute(attr.getValue());
834 }
835 void printOptionalAttrDictWithKeyword(
838 printOptionalAttrDict(attrs, elidedAttrs);
839 }
840
841
842
843 raw_ostream &getStream() const override { return os; }
844
845
846
847 void printFloat(const APFloat &) override {}
848 void printAffineMapOfSSAIds(AffineMapAttr, ValueRange) override {}
851 void increaseIndent() override {}
852 void decreaseIndent() override {}
853 void printOperand(Value) override {}
854 void printOperand(Value, raw_ostream &os) override {
855
856
857
858 os << "%";
859 }
863 void printSymbolName(StringRef) override {}
864 void printSuccessor(Block *) override {}
865 void printSuccessorAndUseList(Block *, ValueRange) override {}
867
868
870
871
872 AliasInitializer &initializer;
873
874
875 mutable llvm::raw_null_ostream os;
876 };
877
879 public:
880 explicit DummyAliasDialectAsmPrinter(AliasInitializer &initializer,
881 bool canBeDeferred,
883 : initializer(initializer), canBeDeferred(canBeDeferred),
884 childIndices(childIndices) {}
885
886
887
888
889 template <typename T, typename... PrintArgs>
890 size_t printAndVisitNestedAliases(T value, PrintArgs &&...printArgs) {
891 printAndVisitNestedAliasesImpl(value, printArgs...);
892 return maxAliasDepth;
893 }
894
895 private:
896
897
898 void printAndVisitNestedAliasesImpl(Attribute attr, bool elideType) {
899 if (!isa(attr.getDialect())) {
901
902
903 } else if (llvm::isa<AffineMapAttr, DenseArrayAttr, FloatAttr, IntegerAttr,
904 IntegerSetAttr, UnitAttr>(attr)) {
905 return;
906 } else if (auto distinctAttr = dyn_cast(attr)) {
907 printAttribute(distinctAttr.getReferencedAttr());
908 } else if (auto dictAttr = dyn_cast(attr)) {
910 printAttribute(nestedAttr.getName());
911 printAttribute(nestedAttr.getValue());
912 }
913 } else if (auto arrayAttr = dyn_cast(attr)) {
914 for (Attribute nestedAttr : arrayAttr.getValue())
915 printAttribute(nestedAttr);
916 } else if (auto typeAttr = dyn_cast(attr)) {
918 } else if (auto locAttr = dyn_cast(attr)) {
919 printAttribute(locAttr.getFallbackLocation());
920 } else if (auto locAttr = dyn_cast(attr)) {
921 if (!isa(locAttr.getChildLoc()))
922 printAttribute(locAttr.getChildLoc());
923 } else if (auto locAttr = dyn_cast(attr)) {
924 printAttribute(locAttr.getCallee());
925 printAttribute(locAttr.getCaller());
926 } else if (auto locAttr = dyn_cast(attr)) {
927 if (Attribute metadata = locAttr.getMetadata())
928 printAttribute(metadata);
929 for (Location nestedLoc : locAttr.getLocations())
930 printAttribute(nestedLoc);
931 }
932
933
934 if (!elideType) {
935 if (auto typedAttr = llvm::dyn_cast(attr)) {
936 Type attrType = typedAttr.getType();
937 if (!llvm::isa(attrType))
939 }
940 }
941 }
942 void printAndVisitNestedAliasesImpl(Type type) {
943 if (!isa(type.getDialect()))
945
946
947 if (auto memrefTy = llvm::dyn_cast(type)) {
948 printType(memrefTy.getElementType());
949 MemRefLayoutAttrInterface layout = memrefTy.getLayout();
950 if (!llvm::isa(layout) || !layout.isIdentity())
951 printAttribute(memrefTy.getLayout());
952 if (memrefTy.getMemorySpace())
953 printAttribute(memrefTy.getMemorySpace());
954 return;
955 }
956
957
958 auto visitFn = [&](auto element) {
959 if (element)
960 (void)printAlias(element);
961 };
963 }
964
965
967 recordAliasResult(initializer.visit(type, canBeDeferred));
968 }
969
970
971 void printAttribute(Attribute attr) override {
972 recordAliasResult(initializer.visit(attr, canBeDeferred));
973 }
974 void printAttributeWithoutType(Attribute attr) override {
975 recordAliasResult(
976 initializer.visit(attr, canBeDeferred, true));
977 }
978 LogicalResult printAlias(Attribute attr) override {
979 printAttribute(attr);
980 return success();
981 }
982 LogicalResult printAlias(Type type) override {
984 return success();
985 }
986
987
988 void recordAliasResult(std::pair<size_t, size_t> aliasDepthAndIndex) {
989 childIndices.push_back(aliasDepthAndIndex.second);
990 if (aliasDepthAndIndex.first > maxAliasDepth)
991 maxAliasDepth = aliasDepthAndIndex.first;
992 }
993
994
995
996 raw_ostream &getStream() const override { return os; }
997
998
999
1000 void printFloat(const APFloat &) override {}
1003 void printSymbolName(StringRef) override {}
1005
1006 LogicalResult pushCyclicPrinting(const void *opaquePointer) override {
1007 return success(cyclicPrintingStack.insert(opaquePointer));
1008 }
1009
1010 void popCyclicPrinting() override { cyclicPrintingStack.pop_back(); }
1011
1012
1013
1015
1016
1017 AliasInitializer &initializer;
1018
1019
1020 bool canBeDeferred;
1021
1022
1024
1025
1026 size_t maxAliasDepth = 0;
1027
1028
1029 mutable llvm::raw_null_ostream os;
1030 };
1031 }
1032
1033
1034
1035
1037 StringRef allowedPunctChars = "$._-") {
1038 assert(!name.empty() && "Shouldn't have an empty name here");
1039
1040 auto validChar = [&](char ch) {
1041 return llvm::isAlnum(ch) || allowedPunctChars.contains(ch);
1042 };
1043
1044 auto copyNameToBuffer = [&] {
1045 for (char ch : name) {
1046 if (validChar(ch))
1047 buffer.push_back(ch);
1048 else if (ch == ' ')
1049 buffer.push_back('_');
1050 else
1051 buffer.append(llvm::utohexstr((unsigned char)ch));
1052 }
1053 };
1054
1055
1056
1057
1058 if (isdigit(name[0]) || (!validChar(name[0]) && name[0] != ' ')) {
1059 buffer.push_back('_');
1060 copyNameToBuffer();
1061 return buffer;
1062 }
1063
1064
1065 for (char ch : name) {
1066 if (!validChar(ch)) {
1067 copyNameToBuffer();
1068 return buffer;
1069 }
1070 }
1071
1072
1073 return name;
1074 }
1075
1076 unsigned AliasInitializer::uniqueAliasNameIndex(
1077 StringRef alias, llvm::StringMap &nameCounts,
1079 if (!usedAliases.count(alias)) {
1080 usedAliases.insert(alias);
1081
1082 return 0;
1083 }
1084
1086
1087 if (isdigit(alias.back()))
1088 probeAlias.push_back('_');
1089
1090 if (nameCounts[probeAlias] == 0)
1091 nameCounts[probeAlias] = 1;
1092
1093
1094 while (true) {
1095 unsigned nameIndex = nameCounts[probeAlias]++;
1096 probeAlias += llvm::utostr(nameIndex);
1097 if (!usedAliases.count(probeAlias)) {
1098 usedAliases.insert(probeAlias);
1099 return nameIndex;
1100 }
1101
1102 probeAlias.resize(alias.size() + isdigit(alias.back()) ? 1 : 0);
1103 }
1104 }
1105
1106
1107
1108 void AliasInitializer::initializeAliases(
1109 llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
1110 llvm::MapVector<const void *, SymbolAlias> &symbolToAlias) {
1112 unprocessedAliases = visitedSymbols.takeVector();
1113 llvm::stable_sort(unprocessedAliases, llvm::less_second());
1114
1115
1116
1117 llvm::BumpPtrAllocator usedAliasAllocator;
1119
1120 llvm::StringMap nameCounts;
1121 for (auto &[symbol, aliasInfo] : unprocessedAliases) {
1122 if (!aliasInfo.alias)
1123 continue;
1124 StringRef alias = *aliasInfo.alias;
1125 unsigned nameIndex = uniqueAliasNameIndex(alias, nameCounts, usedAliases);
1126 symbolToAlias.insert(
1127 {symbol, SymbolAlias(alias, nameIndex, aliasInfo.isType,
1128 aliasInfo.canBeDeferred)});
1129 }
1130 }
1131
1132 void AliasInitializer::initialize(
1134 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias) {
1135
1136
1137
1138 DummyAliasOperationPrinter aliasPrinter(printerFlags, *this);
1139 aliasPrinter.printCustomOrGenericOp(op);
1140
1141
1142 initializeAliases(aliases, attrTypeToAlias);
1143 }
1144
1145 template <typename T, typename... PrintArgs>
1146 std::pair<size_t, size_t> AliasInitializer::visitImpl(
1147 T value, llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
1148 bool canBeDeferred, PrintArgs &&...printArgs) {
1149 auto [it, inserted] = aliases.try_emplace(value.getAsOpaquePointer());
1150 size_t aliasIndex = std::distance(aliases.begin(), it);
1151 if (!inserted) {
1152
1153 if (!canBeDeferred)
1154 markAliasNonDeferrable(aliasIndex);
1155 return {static_cast<size_t>(it->second.aliasDepth), aliasIndex};
1156 }
1157
1158
1159 generateAlias(value, it->second, canBeDeferred);
1160 it->second.isType = std::is_base_of_v<Type, T>;
1161 it->second.canBeDeferred = canBeDeferred;
1162
1163
1165 DummyAliasDialectAsmPrinter printer(*this, canBeDeferred, childAliases);
1166 size_t maxAliasDepth =
1167 printer.printAndVisitNestedAliases(value, printArgs...);
1168
1169
1170 it = std::next(aliases.begin(), aliasIndex);
1171
1172
1173 it->second.childIndices = std::move(childAliases);
1174 if (maxAliasDepth)
1175 it->second.aliasDepth = maxAliasDepth + 1;
1176
1177
1178 return {(size_t)it->second.aliasDepth, aliasIndex};
1179 }
1180
1181 void AliasInitializer::markAliasNonDeferrable(size_t aliasIndex) {
1182 auto *it = std::next(aliases.begin(), aliasIndex);
1183
1184
1185
1186 if (!it->second.canBeDeferred)
1187 return;
1188
1189 it->second.canBeDeferred = false;
1190
1191
1192 for (size_t childIndex : it->second.childIndices)
1193 markAliasNonDeferrable(childIndex);
1194 }
1195
1196 template
1197 void AliasInitializer::generateAlias(T symbol, InProgressAliasInfo &alias,
1198 bool canBeDeferred) {
1200
1203 using InterfaceT = std::conditional_t<std::is_base_of_v<Attribute, T>,
1204 OpAsmAttrInterface, OpAsmTypeInterface>;
1205 if (auto symbolInterface = dyn_cast(symbol)) {
1206 symbolInterfaceResult = symbolInterface.getAlias(aliasOS);
1208 nameBuffer = std::move(aliasBuffer);
1209 assert(!nameBuffer.empty() && "expected valid alias name");
1210 }
1211 }
1212
1213 if (symbolInterfaceResult != OpAsmDialectInterface::AliasResult::FinalAlias) {
1214 for (const auto &interface : interfaces) {
1216 interface.getAlias(symbol, aliasOS);
1218 continue;
1219 nameBuffer = std::move(aliasBuffer);
1220 assert(!nameBuffer.empty() && "expected valid alias name");
1221 if (result == OpAsmDialectInterface::AliasResult::FinalAlias)
1222 break;
1223 }
1224 }
1225
1226 if (nameBuffer.empty())
1227 return;
1228
1230 StringRef name =
1231 sanitizeIdentifier(nameBuffer, tempBuffer, "$_-");
1232 name = name.copy(aliasAllocator);
1233 alias = InProgressAliasInfo(name);
1234 }
1235
1236
1237
1238
1239
1240 namespace {
1241
1242 class AliasState {
1243 public:
1244
1245 void
1248
1249
1250
1251 LogicalResult getAlias(Attribute attr, raw_ostream &os) const;
1252
1253
1254
1255 LogicalResult getAlias(Type ty, raw_ostream &os) const;
1256
1257
1258
1259 void printNonDeferredAliases(AsmPrinter::Impl &p, NewLineCounter &newLine) {
1260 printAliases(p, newLine, false);
1261 }
1262
1263
1264 void printDeferredAliases(AsmPrinter::Impl &p, NewLineCounter &newLine) {
1265 printAliases(p, newLine, true);
1266 }
1267
1268 private:
1269
1270
1271 void printAliases(AsmPrinter::Impl &p, NewLineCounter &newLine,
1272 bool isDeferred);
1273
1274
1275 llvm::MapVector<const void *, SymbolAlias> attrTypeToAlias;
1276
1277
1278 llvm::BumpPtrAllocator aliasAllocator;
1279 };
1280 }
1281
1282 void AliasState::initialize(
1285 AliasInitializer initializer(interfaces, aliasAllocator);
1286 initializer.initialize(op, printerFlags, attrTypeToAlias);
1287 }
1288
1289 LogicalResult AliasState::getAlias(Attribute attr, raw_ostream &os) const {
1291 if (it == attrTypeToAlias.end())
1292 return failure();
1293 it->second.print(os);
1294 return success();
1295 }
1296
1297 LogicalResult AliasState::getAlias(Type ty, raw_ostream &os) const {
1299 if (it == attrTypeToAlias.end())
1300 return failure();
1301 if (!it->second.isPrinted)
1302 return failure();
1303
1304 it->second.print(os);
1305 return success();
1306 }
1307
1308 void AliasState::printAliases(AsmPrinter::Impl &p, NewLineCounter &newLine,
1309 bool isDeferred) {
1310 auto filterFn = [=](const auto &aliasIt) {
1311 return aliasIt.second.canBeDeferred() == isDeferred;
1312 };
1313 for (auto &[opaqueSymbol, alias] :
1314 llvm::make_filter_range(attrTypeToAlias, filterFn)) {
1317
1318 if (alias.isTypeAlias()) {
1321 alias.isPrinted = true;
1322 } else {
1323
1327 else
1329 }
1330
1332 }
1333 }
1334
1335
1336
1337
1338
1339 namespace {
1340
1341
1342 struct BlockInfo {
1343 int ordering;
1344 StringRef name;
1345 };
1346
1347
1348 class SSANameState {
1349 public:
1350
1351 enum : unsigned { NameSentinel = ~0U };
1352
1354 SSANameState() = default;
1355
1356
1357
1358
1359 void printValueID(Value value, bool printResultNo, raw_ostream &stream) const;
1360
1361
1362 void printOperationID(Operation *op, raw_ostream &stream) const;
1363
1364
1365
1367
1368
1369 BlockInfo getBlockInfo(Block *block);
1370
1371
1372
1373
1374 void shadowRegionArgs(Region ®ion, ValueRange namesToUse);
1375
1376 private:
1377
1378 void numberValuesInRegion(Region ®ion);
1379 void numberValuesInBlock(Block &block);
1380 void numberValuesInOp(Operation &op);
1381
1382
1383
1384
1385
1386 void getResultIDAndNumber(OpResult result, Value &lookupValue,
1387 std::optional &lookupResultNo) const;
1388
1389
1390 void setValueName(Value value, StringRef name);
1391
1392
1393
1394 StringRef uniqueValueName(StringRef name);
1395
1396
1397
1400
1401
1402
1404
1405
1406
1407
1409
1410
1411
1413
1414
1415
1416
1417 llvm::ScopedHashTable<StringRef, char> usedNames;
1418 llvm::BumpPtrAllocator usedNameAllocator;
1419
1420
1421 unsigned nextValueID = 0;
1422
1423 unsigned nextArgumentID = 0;
1424
1425 unsigned nextConflictID = 0;
1426
1427
1428
1430 };
1431 }
1432
1434 : printerFlags(printerFlags) {
1435 llvm::SaveAndRestore valueIDSaver(nextValueID);
1436 llvm::SaveAndRestore argumentIDSaver(nextArgumentID);
1437 llvm::SaveAndRestore conflictIDSaver(nextConflictID);
1438
1439
1440
1441
1442 using UsedNamesScopeTy = llvm::ScopedHashTable<StringRef, char>::ScopeTy;
1443 using NamingContext =
1444 std::tuple<Region *, unsigned, unsigned, unsigned, UsedNamesScopeTy *>;
1445
1446
1447 llvm::BumpPtrAllocator allocator;
1448
1449
1450 auto *topLevelNamesScope =
1451 new (allocator.Allocate()) UsedNamesScopeTy(usedNames);
1452
1455 nameContext.push_back(std::make_tuple(®ion, nextValueID, nextArgumentID,
1456 nextConflictID, topLevelNamesScope));
1457
1458 numberValuesInOp(*op);
1459
1460 while (!nameContext.empty()) {
1462 UsedNamesScopeTy *parentScope;
1463
1465
1466 std::tie(region, std::ignore, std::ignore, std::ignore, parentScope) =
1467 nameContext.pop_back_val();
1468 else
1469 std::tie(region, nextValueID, nextArgumentID, nextConflictID,
1470 parentScope) = nameContext.pop_back_val();
1471
1472
1473
1474 while (usedNames.getCurScope() != parentScope) {
1475 usedNames.getCurScope()->~UsedNamesScopeTy();
1476 assert((usedNames.getCurScope() != nullptr || parentScope == nullptr) &&
1477 "top level parentScope must be a nullptr");
1478 }
1479
1480
1481 auto *curNamesScope = new (allocator.Allocate())
1482 UsedNamesScopeTy(usedNames);
1483
1484 numberValuesInRegion(*region);
1485
1488 nameContext.push_back(std::make_tuple(®ion, nextValueID,
1489 nextArgumentID, nextConflictID,
1490 curNamesScope));
1491 }
1492
1493
1494 while (usedNames.getCurScope() != nullptr)
1495 usedNames.getCurScope()->~UsedNamesScopeTy();
1496 }
1497
1498 void SSANameState::printValueID(Value value, bool printResultNo,
1499 raw_ostream &stream) const {
1500 if (!value) {
1501 stream << "<>";
1502 return;
1503 }
1504
1505 std::optional resultNo;
1506 auto lookupValue = value;
1507
1508
1509
1510 if (OpResult result = dyn_cast(value))
1511 getResultIDAndNumber(result, lookupValue, resultNo);
1512
1513 auto it = valueIDs.find(lookupValue);
1514 if (it == valueIDs.end()) {
1515 stream << "<>";
1516 return;
1517 }
1518
1519 stream << '%';
1520 if (it->second != NameSentinel) {
1521 stream << it->second;
1522 } else {
1523 auto nameIt = valueNames.find(lookupValue);
1524 assert(nameIt != valueNames.end() && "Didn't have a name entry?");
1525 stream << nameIt->second;
1526 }
1527
1528 if (resultNo && printResultNo)
1529 stream << '#' << *resultNo;
1530 }
1531
1532 void SSANameState::printOperationID(Operation *op, raw_ostream &stream) const {
1533 auto it = operationIDs.find(op);
1534 if (it == operationIDs.end()) {
1535 stream << "<>";
1536 } else {
1537 stream << '%' << it->second;
1538 }
1539 }
1540
1542 auto it = opResultGroups.find(op);
1543 return it == opResultGroups.end() ? ArrayRef() : it->second;
1544 }
1545
1546 BlockInfo SSANameState::getBlockInfo(Block *block) {
1547 auto it = blockNames.find(block);
1548 BlockInfo invalidBlock{-1, "INVALIDBLOCK"};
1549 return it != blockNames.end() ? it->second : invalidBlock;
1550 }
1551
1552 void SSANameState::shadowRegionArgs(Region ®ion, ValueRange namesToUse) {
1553 assert(!region.empty() && "cannot shadow arguments of an empty region");
1555 "incorrect number of names passed in");
1557 "only KnownIsolatedFromAbove ops can shadow names");
1558
1560 for (unsigned i = 0, e = namesToUse.size(); i != e; ++i) {
1561 auto nameToUse = namesToUse[i];
1562 if (nameToUse == nullptr)
1563 continue;
1564 auto nameToReplace = region.getArgument(i);
1565
1566 nameStr.clear();
1567 llvm::raw_svector_ostream nameStream(nameStr);
1568 printValueID(nameToUse, true, nameStream);
1569
1570
1571 assert(valueIDs[nameToReplace] == NameSentinel);
1572
1573
1574 auto name = StringRef(nameStream.str()).drop_front();
1575
1576
1577 valueNames[nameToReplace] = name.copy(usedNameAllocator);
1578 }
1579 }
1580
1581 namespace {
1582
1583 StringRef maybeGetValueNameFromLoc(Value value, StringRef name) {
1585 return maybeNameLoc.getName();
1586 return name;
1587 }
1588 }
1589
1590 void SSANameState::numberValuesInRegion(Region ®ion) {
1591
1592 bool opAsmOpInterfaceUsed = false;
1593 auto setBlockArgNameFn = [&](Value arg, StringRef name) {
1594 assert(!valueIDs.count(arg) && "arg numbered multiple times");
1595 assert(llvm::cast(arg).getOwner()->getParent() == ®ion &&
1596 "arg not defined in current region");
1597 opAsmOpInterfaceUsed = true;
1599 name = maybeGetValueNameFromLoc(arg, name);
1600 setValueName(arg, name);
1601 };
1602
1605 if (auto asmInterface = dyn_cast(op))
1606 asmInterface.getAsmBlockArgumentNames(region, setBlockArgNameFn);
1607
1608 if (!opAsmOpInterfaceUsed) {
1610 if (auto interface = dyn_cast(arg.getType())) {
1611 interface.getAsmName(
1612 [&](StringRef name) { setBlockArgNameFn(arg, name); });
1613 }
1614 }
1615 }
1616 }
1617 }
1618
1619
1620 unsigned nextBlockID = 0;
1621 for (auto &block : region) {
1622
1623
1624 auto blockInfoIt = blockNames.insert({&block, {-1, ""}});
1625 if (blockInfoIt.second) {
1626
1627
1628 std::string name;
1629 llvm::raw_string_ostream(name) << "^bb" << nextBlockID;
1630 blockInfoIt.first->second.name = StringRef(name).copy(usedNameAllocator);
1631 }
1632 blockInfoIt.first->second.ordering = nextBlockID++;
1633
1634 numberValuesInBlock(block);
1635 }
1636 }
1637
1638 void SSANameState::numberValuesInBlock(Block &block) {
1639
1640
1642 SmallString<32> specialNameBuffer(isEntryBlock ? "arg" : "");
1643 llvm::raw_svector_ostream specialName(specialNameBuffer);
1645 if (valueIDs.count(arg))
1646 continue;
1647 if (isEntryBlock) {
1648 specialNameBuffer.resize(strlen("arg"));
1649 specialName << nextArgumentID++;
1650 }
1651 StringRef specialNameStr = specialName.str();
1653 specialNameStr = maybeGetValueNameFromLoc(arg, specialNameStr);
1654 setValueName(arg, specialNameStr);
1655 }
1656
1657
1658 for (auto &op : block)
1659 numberValuesInOp(op);
1660 }
1661
1662 void SSANameState::numberValuesInOp(Operation &op) {
1663
1665
1666 bool opAsmOpInterfaceUsed = false;
1667 auto setResultNameFn = [&](Value result, StringRef name) {
1668 assert(!valueIDs.count(result) && "result numbered multiple times");
1669 assert(result.getDefiningOp() == &op && "result not defined by 'op'");
1670 opAsmOpInterfaceUsed = true;
1672 name = maybeGetValueNameFromLoc(result, name);
1673 setValueName(result, name);
1674
1675
1676 if (int resultNo = llvm::cast(result).getResultNumber())
1677 resultGroups.push_back(resultNo);
1678 };
1679
1680 auto setBlockNameFn = [&](Block *block, StringRef name) {
1682 "getAsmBlockArgumentNames callback invoked on a block not directly "
1683 "nested under the current operation");
1684 assert(!blockNames.count(block) && "block numbered multiple times");
1687 if (name.data() != tmpBuffer.data()) {
1688 tmpBuffer.append(name);
1689 name = tmpBuffer.str();
1690 }
1691 name = name.copy(usedNameAllocator);
1692 blockNames[block] = {-1, name};
1693 };
1694
1696 if (OpAsmOpInterface asmInterface = dyn_cast(&op)) {
1697 asmInterface.getAsmBlockNames(setBlockNameFn);
1698 asmInterface.getAsmResultNames(setResultNameFn);
1699 }
1700 if (!opAsmOpInterfaceUsed) {
1701
1702
1703 bool allHaveOpAsmTypeInterface =
1705 return isa(type);
1706 });
1707 if (allHaveOpAsmTypeInterface) {
1709 auto interface = cast(result.getType());
1710 interface.getAsmName(
1711 [&](StringRef name) { setResultNameFn(result, name); });
1712 }
1713 }
1714 }
1715 }
1716
1718 if (numResults == 0) {
1719
1721 if (operationIDs.try_emplace(&op, nextValueID).second)
1722 ++nextValueID;
1723 }
1724 return;
1725 }
1727
1730 setValueName(resultBegin, nameLoc.getName());
1731 }
1732 }
1733
1734
1735 if (valueIDs.try_emplace(resultBegin, nextValueID).second)
1736 ++nextValueID;
1737
1738
1739 if (resultGroups.size() != 1) {
1740 llvm::array_pod_sort(resultGroups.begin(), resultGroups.end());
1741 opResultGroups.try_emplace(&op, std::move(resultGroups));
1742 }
1743 }
1744
1745 void SSANameState::getResultIDAndNumber(
1747 std::optional &lookupResultNo) const {
1750 return;
1752
1753
1754
1755 auto resultGroupIt = opResultGroups.find(owner);
1756 if (resultGroupIt == opResultGroups.end()) {
1757
1758 lookupResultNo = resultNo;
1759 lookupValue = owner->getResult(0);
1760 return;
1761 }
1762
1763
1764 ArrayRef resultGroups = resultGroupIt->second;
1765 const auto *it = llvm::upper_bound(resultGroups, resultNo);
1766 int groupResultNo = 0, groupSize = 0;
1767
1768
1769 if (it == resultGroups.end()) {
1770 groupResultNo = resultGroups.back();
1771 groupSize = static_cast<int>(owner->getNumResults()) - resultGroups.back();
1772 } else {
1773
1774 groupResultNo = *std::prev(it);
1775 groupSize = *it - groupResultNo;
1776 }
1777
1778
1779 if (groupSize != 1)
1780 lookupResultNo = resultNo - groupResultNo;
1781 lookupValue = owner->getResult(groupResultNo);
1782 }
1783
1784 void SSANameState::setValueName(Value value, StringRef name) {
1785
1786 if (name.empty()) {
1787 valueIDs[value] = nextValueID++;
1788 return;
1789 }
1790
1791 valueIDs[value] = NameSentinel;
1792 valueNames[value] = uniqueValueName(name);
1793 }
1794
1795 StringRef SSANameState::uniqueValueName(StringRef name) {
1798
1799
1800 if (!usedNames.count(name)) {
1801 name = name.copy(usedNameAllocator);
1802 } else {
1803
1804
1805
1807 probeName.push_back('_');
1808 while (true) {
1809 probeName += llvm::utostr(nextConflictID++);
1810 if (!usedNames.count(probeName)) {
1811 name = probeName.str().copy(usedNameAllocator);
1812 break;
1813 }
1814 probeName.resize(name.size() + 1);
1815 }
1816 }
1817
1818 usedNames.insert(name, char());
1819 return name;
1820 }
1821
1822
1823
1824
1825
1826 namespace {
1827
1828 class DistinctState {
1829 public:
1830
1832
1833 private:
1834 uint64_t distinctCounter = 0;
1836 };
1837 }
1838
1839 uint64_t DistinctState::getId(DistinctAttr distinctAttr) {
1840 auto [it, inserted] =
1841 distinctAttrMap.try_emplace(distinctAttr, distinctCounter);
1842 if (inserted)
1843 distinctCounter++;
1844 return it->getSecond();
1845 }
1846
1847
1848
1849
1850
1851 AsmParsedResourceEntry::~AsmParsedResourceEntry() = default;
1852 AsmResourceBuilder::~AsmResourceBuilder() = default;
1853 AsmResourceParser::~AsmResourceParser() = default;
1854 AsmResourcePrinter::~AsmResourcePrinter() = default;
1855
1857 switch (kind) {
1858 case AsmResourceEntryKind::Blob:
1859 return "blob";
1860 case AsmResourceEntryKind::Bool:
1861 return "bool";
1862 case AsmResourceEntryKind::String:
1863 return "string";
1864 }
1865 llvm_unreachable("unknown AsmResourceEntryKind");
1866 }
1867
1869 std::unique_ptr &collection = keyToResources[key.str()];
1870 if (!collection)
1871 collection = std::make_unique(key);
1872 return *collection;
1873 }
1874
1875 std::vector<std::unique_ptr>
1877 std::vector<std::unique_ptr> printers;
1878 for (auto &it : keyToResources) {
1879 ResourceCollection *collection = it.second.get();
1881 return collection->buildResources(op, builder);
1882 };
1883 printers.emplace_back(
1885 }
1886 return printers;
1887 }
1888
1889 LogicalResult FallbackAsmResourceMap::ResourceCollection::parseResource(
1891 switch (entry.getKind()) {
1893 FailureOr blob = entry.parseAsBlob();
1894 if (failed(blob))
1895 return failure();
1896 resources.emplace_back(entry.getKey(), std::move(*blob));
1897 return success();
1898 }
1900 FailureOr value = entry.parseAsBool();
1901 if (failed(value))
1902 return failure();
1903 resources.emplace_back(entry.getKey(), *value);
1904 break;
1905 }
1907 FailureOrstd::string str = entry.parseAsString();
1908 if (failed(str))
1909 return failure();
1910 resources.emplace_back(entry.getKey(), std::move(*str));
1911 break;
1912 }
1913 }
1914 return success();
1915 }
1916
1917 void FallbackAsmResourceMap::ResourceCollection::buildResources(
1919 for (const auto &entry : resources) {
1920 if (const auto *value = std::get_if(&entry.value))
1921 builder.buildBlob(entry.key, *value);
1922 else if (const auto *value = std::get_if(&entry.value))
1923 builder.buildBool(entry.key, *value);
1924 else if (const auto *value = std::get_ifstd::string(&entry.value))
1926 else
1927 llvm_unreachable("unknown AsmResourceEntryKind");
1928 }
1929 }
1930
1931
1932
1933
1934
1935 namespace mlir {
1936 namespace detail {
1938 public:
1941 : interfaces(op->getContext()), nameState(op, printerFlags),
1942 printerFlags(printerFlags), locationMap(locationMap) {}
1945 : interfaces(ctx), printerFlags(printerFlags), locationMap(locationMap) {}
1946
1947
1949 aliasState.initialize(op, printerFlags, interfaces);
1950 }
1951
1952
1954
1955
1957
1958
1960
1961
1962
1964 return interfaces;
1965 }
1966
1967
1969 return llvm::make_pointee_range(externalResourcePrinters);
1970 }
1971
1972
1974
1975
1976
1978 if (locationMap)
1979 (*locationMap)[op] = std::make_pair(line, col);
1980 }
1981
1982
1985 return dialectResources;
1986 }
1987
1989 return success(cyclicPrintingStack.insert(opaquePointer));
1990 }
1991
1993
1994 private:
1995
1997
1998
2000
2001
2003
2004
2005 AliasState aliasState;
2006
2007
2008 SSANameState nameState;
2009
2010
2011 DistinctState distinctState;
2012
2013
2015
2016
2018
2019
2020
2022
2023
2025 };
2026
2027 template
2029 llvm::interleave(
2030 shape, stream,
2031 [&stream](const auto &dimSize) {
2032 if (ShapedType::isDynamic(dimSize))
2033 stream << "?";
2034 else
2035 stream << dimSize;
2036 },
2037 "x");
2038 }
2039
2040 }
2041 }
2042
2043
2044
2045
2050 return printerFlags;
2051
2052
2053
2054 auto parentThreadId = llvm::get_threadid();
2056 if (parentThreadId == llvm::get_threadid()) {
2057 LLVM_DEBUG({
2058 diag.print(llvm::dbgs());
2059 llvm::dbgs() << "\n";
2060 });
2061 return success();
2062 }
2063 return failure();
2064 });
2065 if (failed(verify(op))) {
2066 LLVM_DEBUG(llvm::dbgs()
2068 << "' failed to verify and will be printed in generic form\n");
2070 }
2071
2072 return printerFlags;
2073 }
2074
2079 if (map)
2081 }
2084 : impl(std::make_unique<AsmStateImpl>(ctx, printerFlags, locationMap)) {
2085 if (map)
2087 }
2089
2091 return impl->getPrinterFlags();
2092 }
2093
2095 std::unique_ptr printer) {
2096 impl->externalResourcePrinters.emplace_back(std::move(printer));
2097 }
2098
2101 return impl->getDialectResources();
2102 }
2103
2104
2105
2106
2107
2109 : os(os), state(state), printerFlags(state.getPrinterFlags()) {}
2110
2112
2114 return;
2115
2116 os << " ";
2117 printLocation(loc, allowAlias);
2118 }
2119
2121 bool isTopLevel) {
2122
2123 if (!isTopLevel && succeeded(state.getAliasState().getAlias(loc, os)))
2124 return;
2125
2127 .Case([&](OpaqueLoc loc) {
2128 printLocationInternal(loc.getFallbackLocation(), pretty);
2129 })
2130 .Case([&](UnknownLoc loc) {
2131 if (pretty)
2132 os << "[unknown]";
2133 else
2134 os << "unknown";
2135 })
2137 if (pretty)
2138 os << loc.getFilename().getValue();
2139 else
2140 printEscapedString(loc.getFilename());
2141 if (loc.getEndColumn() == loc.getStartColumn() &&
2142 loc.getStartLine() == loc.getEndLine()) {
2143 os << ':' << loc.getStartLine() << ':' << loc.getStartColumn();
2144 return;
2145 }
2146 if (loc.getStartLine() == loc.getEndLine()) {
2147 os << ':' << loc.getStartLine() << ':' << loc.getStartColumn()
2148 << " to :" << loc.getEndColumn();
2149 return;
2150 }
2151 os << ':' << loc.getStartLine() << ':' << loc.getStartColumn() << " to "
2152 << loc.getEndLine() << ':' << loc.getEndColumn();
2153 })
2154 .Case([&](NameLoc loc) {
2155 printEscapedString(loc.getName());
2156
2157
2158 auto childLoc = loc.getChildLoc();
2159 if (!llvm::isa(childLoc)) {
2160 os << '(';
2161 printLocationInternal(childLoc, pretty);
2162 os << ')';
2163 }
2164 })
2165 .Case([&](CallSiteLoc loc) {
2166 Location caller = loc.getCaller();
2167 Location callee = loc.getCallee();
2168 if (!pretty)
2169 os << "callsite(";
2170 printLocationInternal(callee, pretty);
2171 if (pretty) {
2172 if (llvm::isa(callee)) {
2173 if (llvm::isa(caller)) {
2174 os << " at ";
2175 } else {
2176 os << newLine << " at ";
2177 }
2178 } else {
2179 os << newLine << " at ";
2180 }
2181 } else {
2182 os << " at ";
2183 }
2184 printLocationInternal(caller, pretty);
2185 if (!pretty)
2186 os << ")";
2187 })
2188 .Case([&](FusedLoc loc) {
2189 if (!pretty)
2190 os << "fused";
2191 if (Attribute metadata = loc.getMetadata()) {
2192 os << '<';
2194 os << '>';
2195 }
2196 os << '[';
2197 interleave(
2198 loc.getLocations(),
2199 [&](Location loc) { printLocationInternal(loc, pretty); },
2200 [&]() { os << ", "; });
2201 os << ']';
2202 })
2203 .Default([&](LocationAttr loc) {
2204 // Assumes that this is a dialect-specific attribute and prints it
2205 // directly.
2206 printAttribute(loc);
2207 });
2208 }
2209
2210
2211
2212 static void printFloatValue(const APFloat &apValue, raw_ostream &os,
2213 bool *printedHex = nullptr) {
2214 // We would like to output the FP constant value in exponential notation,
2215 // but we cannot do this if doing so will lose precision. Check here to
2216 // make sure that we only output it in exponential format if we can parse
2217 // the value back and get the same value.
2218 bool isInf = apValue.isInfinity();
2219 bool isNaN = apValue.isNaN();
2220 if (!isInf && !isNaN) {
2221 SmallString<128> strValue;
2222 apValue.toString(strValue, /*FormatPrecision=*/6, /*FormatMaxPadding=*/0,
2223 /*TruncateZero=*/false);
2224
2225 // Check to make sure that the stringized number is not some string like
2226 // "Inf" or NaN, that atof will accept, but the lexer will not. Check
2227 // that the string matches the "[-+]?[0-9]" regex.
2228 assert(((strValue[0] >= '0' && strValue[0] <= '9') ||
2229 ((strValue[0] == '-' || strValue[0] == '+') &&
2230 (strValue[1] >= '0' && strValue[1] <= '9'))) &&
2231 "[-+]?[0-9] regex does not match!");
2232
2233
2234
2235 if (APFloat(apValue.getSemantics(), strValue).bitwiseIsEqual(apValue)) {
2236 os << strValue;
2237 return;
2238 }
2239
2240
2241
2242 strValue.clear();
2243 apValue.toString(strValue);
2244
2245
2246 if (strValue.str().contains('.')) {
2247 os << strValue;
2248 return;
2249 }
2250 }
2251
2252
2253
2254 if (printedHex)
2255 *printedHex = true;
2257 APInt apInt = apValue.bitcastToAPInt();
2258 apInt.toString(str, 16, false,
2259 true);
2260 os << str;
2261 }
2262
2265 return printLocationInternal(loc, true, true);
2266
2267 os << "loc(";
2268 if (!allowAlias || failed(printAlias(loc)))
2269 printLocationInternal(loc, false, true);
2270 os << ')';
2271 }
2272
2273
2274
2275
2277
2278 if (symName.empty() || !isalpha(symName.front()))
2279 return false;
2280
2281
2282
2283 symName = symName.drop_while(
2284 [](char c) { return llvm::isAlnum(c) || c == '.' || c == '_'; });
2285 if (symName.empty())
2286 return true;
2287
2288
2289
2290 return symName.front() == '<' && symName.back() == '>';
2291 }
2292
2293
2295 StringRef dialectName, StringRef symString) {
2296 os << symPrefix << dialectName;
2297
2298
2299
2301 os << '.' << symString;
2302 return;
2303 }
2304
2305 os << '<' << symString << '>';
2306 }
2307
2308
2309 static bool isBareIdentifier(StringRef name) {
2310 // By making this unsigned, the value passed in to isalnum will always be
2311 // in the range 0-255. This is important when building with MSVC because
2312 // its implementation will assert. This situation can arise when dealing
2313 // with UTF-8 multibyte characters.
2314 if (name.empty() || (!isalpha(name[0]) && name[0] != '_'))
2315 return false;
2316 return llvm::all_of(name.drop_front(), [](unsigned char c) {
2317 return isalnum(c) || c == '_' || c == '$' || c == '.';
2318 });
2319 }
2320
2321
2322
2323 static void printKeywordOrString(StringRef keyword, raw_ostream &os) {
2324 // If it can be represented as a bare identifier, write it directly.
2325 if (isBareIdentifier(keyword)) {
2326 os << keyword;
2327 return;
2328 }
2329
2330 // Otherwise, output the keyword wrapped in quotes with proper escaping.
2331 os << "\"";
2332 printEscapedString(keyword, os);
2333 os << '"';
2334 }
2335
2336
2337
2338
2339 static void printSymbolReference(StringRef symbolRef, raw_ostream &os) {
2340 if (symbolRef.empty()) {
2341 os << "@<>";
2342 return;
2343 }
2344 os << '@';
2345 printKeywordOrString(symbolRef, os);
2346 }
2347
2348 // Print out a valid ElementsAttr that is succinct and can represent any
2349 // potential shape/type, for use when eliding a large ElementsAttr.
2350 //
2351 // We choose to use a dense resource ElementsAttr literal with conspicuous
2352 // content to hopefully alert readers to the fact that this has been elided.
2353 static void printElidedElementsAttr(raw_ostream &os) {
2354 os << R"(dense_resource<__elided__>)";
2355 }
2356
2357 void AsmPrinter::Impl::printResourceHandle(
2358 const AsmDialectResourceHandle &resource) {
2359 auto *interface = cast(resource.getDialect());
2360 ::printKeywordOrString(interface->getResourceKey(resource), os);
2361 state.getDialectResources()[resource.getDialect()].insert(resource);
2362 }
2363
2364 LogicalResult AsmPrinter::Impl::printAlias(Attribute attr) {
2365 return state.getAliasState().getAlias(attr, os);
2366 }
2367
2368 LogicalResult AsmPrinter::Impl::printAlias(Type type) {
2369 return state.getAliasState().getAlias(type, os);
2370 }
2371
2372 void AsmPrinter::Impl::printAttribute(Attribute attr,
2373 AttrTypeElision typeElision) {
2374 if (!attr) {
2375 os << "<>";
2376 return;
2377 }
2378
2379 // Try to print an alias for this attribute.
2380 if (succeeded(printAlias(attr)))
2381 return;
2382 return printAttributeImpl(attr, typeElision);
2383 }
2384
2385 void AsmPrinter::Impl::printAttributeImpl(Attribute attr,
2386 AttrTypeElision typeElision) {
2387 if (!isa(attr.getDialect())) {
2388 printDialectAttribute(attr);
2389 } else if (auto opaqueAttr = llvm::dyn_cast(attr)) {
2390 printDialectSymbol(os, "#", opaqueAttr.getDialectNamespace(),
2391 opaqueAttr.getAttrData());
2392 } else if (llvm::isa(attr)) {
2393 os << "unit";
2394 return;
2395 } else if (auto distinctAttr = llvm::dyn_cast(attr)) {
2396 os << "distinct[" << state.getDistinctState().getId(distinctAttr) << "]<";
2397 if (!llvm::isa(distinctAttr.getReferencedAttr())) {
2398 printAttribute(distinctAttr.getReferencedAttr());
2399 }
2400 os << '>';
2401 return;
2402 } else if (auto dictAttr = llvm::dyn_cast(attr)) {
2403 os << '{';
2404 interleaveComma(dictAttr.getValue(),
2405 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2406 os << '}';
2407
2408 } else if (auto intAttr = llvm::dyn_cast(attr)) {
2409 Type intType = intAttr.getType();
2410 if (intType.isSignlessInteger(1)) {
2411 os << (intAttr.getValue().getBoolValue() ? "true" : "false");
2412
2413 // Boolean integer attributes always elides the type.
2414 return;
2415 }
2416
2417 // Only print attributes as unsigned if they are explicitly unsigned or are
2418 // signless 1-bit values. Indexes, signed values, and multi-bit signless
2419 // values print as signed.
2420 bool isUnsigned =
2421 intType.isUnsignedInteger() || intType.isSignlessInteger(1);
2422 intAttr.getValue().print(os, !isUnsigned);
2423
2424 // IntegerAttr elides the type if I64.
2425 if (typeElision == AttrTypeElision::May && intType.isSignlessInteger(64))
2426 return;
2427
2428 } else if (auto floatAttr = llvm::dyn_cast(attr)) {
2429 bool printedHex = false;
2430 printFloatValue(floatAttr.getValue(), os, &printedHex);
2431
2432 // FloatAttr elides the type if F64.
2433 if (typeElision == AttrTypeElision::May && floatAttr.getType().isF64() &&
2434 !printedHex)
2435 return;
2436
2437 } else if (auto strAttr = llvm::dyn_cast(attr)) {
2438 printEscapedString(strAttr.getValue());
2439
2440 } else if (auto arrayAttr = llvm::dyn_cast(attr)) {
2441 os << '[';
2442 interleaveComma(arrayAttr.getValue(), [&](Attribute attr) {
2443 printAttribute(attr, AttrTypeElision::May);
2444 });
2445 os << ']';
2446
2447 } else if (auto affineMapAttr = llvm::dyn_cast(attr)) {
2448 os << "affine_map<";
2449 affineMapAttr.getValue().print(os);
2450 os << '>';
2451
2452 // AffineMap always elides the type.
2453 return;
2454
2455 } else if (auto integerSetAttr = llvm::dyn_cast(attr)) {
2456 os << "affine_set<";
2457 integerSetAttr.getValue().print(os);
2458 os << '>';
2459
2460 // IntegerSet always elides the type.
2461 return;
2462
2463 } else if (auto typeAttr = llvm::dyn_cast(attr)) {
2464 printType(typeAttr.getValue());
2465
2466 } else if (auto refAttr = llvm::dyn_cast(attr)) {
2467 printSymbolReference(refAttr.getRootReference().getValue(), os);
2468 for (FlatSymbolRefAttr nestedRef : refAttr.getNestedReferences()) {
2469 os << "::";
2470 printSymbolReference(nestedRef.getValue(), os);
2471 }
2472
2473 } else if (auto intOrFpEltAttr =
2474 llvm::dyn_cast(attr)) {
2475 if (printerFlags.shouldElideElementsAttr(intOrFpEltAttr)) {
2476 printElidedElementsAttr(os);
2477 } else {
2478 os << "dense<";
2479 printDenseIntOrFPElementsAttr(intOrFpEltAttr, /*allowHex=*/true);
2480 os << '>';
2481 }
2482
2483 } else if (auto strEltAttr = llvm::dyn_cast(attr)) {
2484 if (printerFlags.shouldElideElementsAttr(strEltAttr)) {
2485 printElidedElementsAttr(os);
2486 } else {
2487 os << "dense<";
2488 printDenseStringElementsAttr(strEltAttr);
2489 os << '>';
2490 }
2491
2492 } else if (auto sparseEltAttr = llvm::dyn_cast(attr)) {
2493 if (printerFlags.shouldElideElementsAttr(sparseEltAttr.getIndices()) ||
2494 printerFlags.shouldElideElementsAttr(sparseEltAttr.getValues())) {
2495 printElidedElementsAttr(os);
2496 } else {
2497 os << "sparse<";
2498 DenseIntElementsAttr indices = sparseEltAttr.getIndices();
2499 if (indices.getNumElements() != 0) {
2500 printDenseIntOrFPElementsAttr(indices, /*allowHex=*/false);
2501 os << ", ";
2502 printDenseElementsAttr(sparseEltAttr.getValues(), /*allowHex=*/true);
2503 }
2504 os << '>';
2505 }
2506 } else if (auto stridedLayoutAttr = llvm::dyn_cast(attr)) {
2507 stridedLayoutAttr.print(os);
2508 } else if (auto denseArrayAttr = llvm::dyn_cast(attr)) {
2509 os << "array<";
2510 printType(denseArrayAttr.getElementType());
2511 if (!denseArrayAttr.empty()) {
2512 os << ": ";
2513 printDenseArrayAttr(denseArrayAttr);
2514 }
2515 os << ">";
2516 return;
2517 } else if (auto resourceAttr =
2518 llvm::dyn_cast(attr)) {
2519 os << "dense_resource<";
2520 printResourceHandle(resourceAttr.getRawHandle());
2521 os << ">";
2522 } else if (auto locAttr = llvm::dyn_cast(attr)) {
2523 printLocation(locAttr);
2524 } else {
2525 llvm::report_fatal_error("Unknown builtin attribute");
2526 }
2527 // Don't print the type if we must elide it, or if it is a None type.
2528 if (typeElision != AttrTypeElision::Must) {
2529 if (auto typedAttr = llvm::dyn_cast(attr)) {
2530 Type attrType = typedAttr.getType();
2531 if (!llvm::isa(attrType)) {
2532 os << " : ";
2533 printType(attrType);
2534 }
2535 }
2536 }
2537 }
2538
2539
2540 static void printDenseIntElement(const APInt &value, raw_ostream &os,
2541 Type type) {
2542 if (type.isInteger(1))
2543 os << (value.getBoolValue() ? "true" : "false");
2544 else
2545 value.print(os, !type.isUnsignedInteger());
2546 }
2547
2548 static void
2549 printDenseElementsAttrImpl(bool isSplat, ShapedType type, raw_ostream &os,
2550 function_ref<void(unsigned)> printEltFn) {
2551 // Special case for 0-d and splat tensors.
2552 if (isSplat)
2553 return printEltFn(0);
2554
2555 // Special case for degenerate tensors.
2556 auto numElements = type.getNumElements();
2557 if (numElements == 0)
2558 return;
2559
2560 // We use a mixed-radix counter to iterate through the shape. When we bump a
2561 // non-least-significant digit, we emit a close bracket. When we next emit an
2562 // element we re-open all closed brackets.
2563
2564 // The mixed-radix counter, with radices in 'shape'.
2565 int64_t rank = type.getRank();
2566 SmallVector<unsigned, 4> counter(rank, 0);
2567 // The number of brackets that have been opened and not closed.
2568 unsigned openBrackets = 0;
2569
2570 auto shape = type.getShape();
2571 auto bumpCounter = [&] {
2572 // Bump the least significant digit.
2573 ++counter[rank - 1];
2574 // Iterate backwards bubbling back the increment.
2575 for (unsigned i = rank - 1; i > 0; --i)
2576 if (counter[i] >= shape[i]) {
2577 // Index 'i' is rolled over. Bump (i-1) and close a bracket.
2578 counter[i] = 0;
2579 ++counter[i - 1];
2580 --openBrackets;
2581 os << ']';
2582 }
2583 };
2584
2585 for (unsigned idx = 0, e = numElements; idx != e; ++idx) {
2586 if (idx != 0)
2587 os << ", ";
2588 while (openBrackets++ < rank)
2589 os << '[';
2590 openBrackets = rank;
2591 printEltFn(idx);
2592 bumpCounter();
2593 }
2594 while (openBrackets-- > 0)
2595 os << ']';
2596 }
2597
2598 void AsmPrinter::Impl::printDenseElementsAttr(DenseElementsAttr attr,
2599 bool allowHex) {
2600 if (auto stringAttr = llvm::dyn_cast(attr))
2601 return printDenseStringElementsAttr(stringAttr);
2602
2603 printDenseIntOrFPElementsAttr(llvm::cast(attr),
2604 allowHex);
2605 }
2606
2607 void AsmPrinter::Impl::printDenseIntOrFPElementsAttr(
2608 DenseIntOrFPElementsAttr attr, bool allowHex) {
2609 auto type = attr.getType();
2610 auto elementType = type.getElementType();
2611
2612 // Check to see if we should format this attribute as a hex string.
2613 if (allowHex && printerFlags.shouldPrintElementsAttrWithHex(attr)) {
2614 ArrayRef rawData = attr.getRawData();
2615 if (llvm::endianness::native == llvm::endianness::big) {
2616 // Convert endianess in big-endian(BE) machines. `rawData` is BE in BE
2617 // machines. It is converted here to print in LE format.
2618 SmallVector<char, 64> outDataVec(rawData.size());
2619 MutableArrayRef convRawData(outDataVec);
2620 DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
2621 rawData, convRawData, type);
2622 printHexString(convRawData);
2623 } else {
2624 printHexString(rawData);
2625 }
2626
2627 return;
2628 }
2629
2630 if (ComplexType complexTy = llvm::dyn_cast(elementType)) {
2631 Type complexElementType = complexTy.getElementType();
2632 // Note: The if and else below had a common lambda function which invoked
2633 // printDenseElementsAttrImpl. This lambda was hitting a bug in gcc 9.1,9.2
2634 // and hence was replaced.
2635 if (llvm::isa(complexElementType)) {
2636 auto valueIt = attr.value_begin<std::complex>();
2637 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2638 auto complexValue = *(valueIt + index);
2639 os << "(";
2640 printDenseIntElement(complexValue.real(), os, complexElementType);
2641 os << ",";
2642 printDenseIntElement(complexValue.imag(), os, complexElementType);
2643 os << ")";
2644 });
2645 } else {
2646 auto valueIt = attr.value_begin<std::complex>();
2647 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2648 auto complexValue = *(valueIt + index);
2649 os << "(";
2650 printFloatValue(complexValue.real(), os);
2651 os << ",";
2652 printFloatValue(complexValue.imag(), os);
2653 os << ")";
2654 });
2655 }
2656 } else if (elementType.isIntOrIndex()) {
2657 auto valueIt = attr.value_begin();
2658 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2659 printDenseIntElement(*(valueIt + index), os, elementType);
2660 });
2661 } else {
2662 assert(llvm::isa(elementType) && "unexpected element type");
2663 auto valueIt = attr.value_begin();
2664 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2665 printFloatValue(*(valueIt + index), os);
2666 });
2667 }
2668 }
2669
2670 void AsmPrinter::Impl::printDenseStringElementsAttr(
2671 DenseStringElementsAttr attr) {
2672 ArrayRef data = attr.getRawStringData();
2673 auto printFn = [&](unsigned index) { printEscapedString(data[index]); };
2674 printDenseElementsAttrImpl(attr.isSplat(), attr.getType(), os, printFn);
2675 }
2676
2677 void AsmPrinter::Impl::printDenseArrayAttr(DenseArrayAttr attr) {
2678 Type type = attr.getElementType();
2679 unsigned bitwidth = type.isInteger(1) ? 8 : type.getIntOrFloatBitWidth();
2680 unsigned byteSize = bitwidth / 8;
2681 ArrayRef data = attr.getRawData();
2682
2683 auto printElementAt = [&](unsigned i) {
2684 APInt value(bitwidth, 0);
2685 if (bitwidth) {
2686 llvm::LoadIntFromMemory(
2687 value, reinterpret_cast<const uint8_t *>(data.begin() + byteSize * i),
2688 byteSize);
2689 }
2690 // Print the data as-is or as a float.
2691 if (type.isIntOrIndex()) {
2692 printDenseIntElement(value, getStream(), type);
2693 } else {
2694 APFloat fltVal(llvm::cast(type).getFloatSemantics(), value);
2695 printFloatValue(fltVal, getStream());
2696 }
2697 };
2698 llvm::interleaveComma(llvm::seq(0, attr.size()), getStream(),
2699 printElementAt);
2700 }
2701
2702 void AsmPrinter::Impl::printType(Type type) {
2703 if (!type) {
2704 os << "<>";
2705 return;
2706 }
2707
2708 // Try to print an alias for this type.
2709 if (succeeded(printAlias(type)))
2710 return;
2711 return printTypeImpl(type);
2712 }
2713
2714 void AsmPrinter::Impl::printTypeImpl(Type type) {
2715 TypeSwitch(type)
2716 .Case([&](OpaqueType opaqueTy) {
2717 printDialectSymbol(os, "!", opaqueTy.getDialectNamespace(),
2718 opaqueTy.getTypeData());
2719 })
2720 .Case([&](Type) { os << "index"; })
2721 .Case([&](Type) { os << "f4E2M1FN"; })
2722 .Case([&](Type) { os << "f6E2M3FN"; })
2723 .Case([&](Type) { os << "f6E3M2FN"; })
2724 .Case([&](Type) { os << "f8E5M2"; })
2725 .Case([&](Type) { os << "f8E4M3"; })
2726 .Case([&](Type) { os << "f8E4M3FN"; })
2727 .Case([&](Type) { os << "f8E5M2FNUZ"; })
2728 .Case([&](Type) { os << "f8E4M3FNUZ"; })
2729 .Case([&](Type) { os << "f8E4M3B11FNUZ"; })
2730 .Case([&](Type) { os << "f8E3M4"; })
2731 .Case([&](Type) { os << "f8E8M0FNU"; })
2732 .Case([&](Type) { os << "bf16"; })
2733 .Case([&](Type) { os << "f16"; })
2734 .Case([&](Type) { os << "tf32"; })
2735 .Case([&](Type) { os << "f32"; })
2736 .Case([&](Type) { os << "f64"; })
2737 .Case([&](Type) { os << "f80"; })
2738 .Case([&](Type) { os << "f128"; })
2739 .Case([&](IntegerType integerTy) {
2740 if (integerTy.isSigned())
2741 os << 's';
2742 else if (integerTy.isUnsigned())
2743 os << 'u';
2744 os << 'i' << integerTy.getWidth();
2745 })
2746 .Case([&](FunctionType funcTy) {
2747 os << '(';
2748 interleaveComma(funcTy.getInputs(), [&](Type ty) { printType(ty); });
2749 os << ") -> ";
2750 ArrayRef results = funcTy.getResults();
2751 if (results.size() == 1 && !llvm::isa(results[0])) {
2752 printType(results[0]);
2753 } else {
2754 os << '(';
2755 interleaveComma(results, [&](Type ty) { printType(ty); });
2756 os << ')';
2757 }
2758 })
2759 .Case([&](VectorType vectorTy) {
2760 auto scalableDims = vectorTy.getScalableDims();
2761 os << "vector<";
2762 auto vShape = vectorTy.getShape();
2763 unsigned lastDim = vShape.size();
2764 unsigned dimIdx = 0;
2765 for (dimIdx = 0; dimIdx < lastDim; dimIdx++) {
2766 if (!scalableDims.empty() && scalableDims[dimIdx])
2767 os << '[';
2768 os << vShape[dimIdx];
2769 if (!scalableDims.empty() && scalableDims[dimIdx])
2770 os << ']';
2771 os << 'x';
2772 }
2773 printType(vectorTy.getElementType());
2774 os << '>';
2775 })
2776 .Case([&](RankedTensorType tensorTy) {
2777 os << "tensor<";
2778 printDimensionList(tensorTy.getShape());
2779 if (!tensorTy.getShape().empty())
2780 os << 'x';
2781 printType(tensorTy.getElementType());
2782 // Only print the encoding attribute value if set.
2783 if (tensorTy.getEncoding()) {
2784 os << ", ";
2785 printAttribute(tensorTy.getEncoding());
2786 }
2787 os << '>';
2788 })
2789 .Case([&](UnrankedTensorType tensorTy) {
2790 os << "tensor<*x";
2791 printType(tensorTy.getElementType());
2792 os << '>';
2793 })
2794 .Case([&](MemRefType memrefTy) {
2795 os << "memref<";
2796 printDimensionList(memrefTy.getShape());
2797 if (!memrefTy.getShape().empty())
2798 os << 'x';
2799 printType(memrefTy.getElementType());
2800 MemRefLayoutAttrInterface layout = memrefTy.getLayout();
2801 if (!llvm::isa(layout) || !layout.isIdentity()) {
2802 os << ", ";
2803 printAttribute(memrefTy.getLayout(), AttrTypeElision::May);
2804 }
2805 // Only print the memory space if it is the non-default one.
2806 if (memrefTy.getMemorySpace()) {
2807 os << ", ";
2808 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2809 }
2810 os << '>';
2811 })
2812 .Case([&](UnrankedMemRefType memrefTy) {
2813 os << "memref<*x";
2814 printType(memrefTy.getElementType());
2815 // Only print the memory space if it is the non-default one.
2816 if (memrefTy.getMemorySpace()) {
2817 os << ", ";
2818 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2819 }
2820 os << '>';
2821 })
2822 .Case([&](ComplexType complexTy) {
2823 os << "complex<";
2824 printType(complexTy.getElementType());
2825 os << '>';
2826 })
2827 .Case([&](TupleType tupleTy) {
2828 os << "tuple<";
2829 interleaveComma(tupleTy.getTypes(),
2830 [&](Type type) { printType(type); });
2831 os << '>';
2832 })
2833 .Case([&](Type) { os << "none"; })
2834 .Default([&](Type type) { return printDialectType(type); });
2835 }
2836
2837 void AsmPrinter::Impl::printOptionalAttrDict(ArrayRef attrs,
2838 ArrayRef elidedAttrs,
2839 bool withKeyword) {
2840 // If there are no attributes, then there is nothing to be done.
2841 if (attrs.empty())
2842 return;
2843
2844 // Functor used to print a filtered attribute list.
2845 auto printFilteredAttributesFn = [&](auto filteredAttrs) {
2846 // Print the 'attributes' keyword if necessary.
2847 if (withKeyword)
2848 os << " attributes";
2849
2850 // Otherwise, print them all out in braces.
2851 os << " {";
2852 interleaveComma(filteredAttrs,
2853 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2854 os << '}';
2855 };
2856
2857 // If no attributes are elided, we can directly print with no filtering.
2858 if (elidedAttrs.empty())
2859 return printFilteredAttributesFn(attrs);
2860
2861 // Otherwise, filter out any attributes that shouldn't be included.
2862 llvm::SmallDenseSet elidedAttrsSet(elidedAttrs.begin(),
2863 elidedAttrs.end());
2864 auto filteredAttrs = llvm::make_filter_range(attrs, [&](NamedAttribute attr) {
2865 return !elidedAttrsSet.contains(attr.getName().strref());
2866 });
2867 if (!filteredAttrs.empty())
2868 printFilteredAttributesFn(filteredAttrs);
2869 }
2870 void AsmPrinter::Impl::printNamedAttribute(NamedAttribute attr) {
2871 // Print the name without quotes if possible.
2872 ::printKeywordOrString(attr.getName().strref(), os);
2873
2874 // Pretty printing elides the attribute value for unit attributes.
2875 if (llvm::isa(attr.getValue()))
2876 return;
2877
2878 os << " = ";
2879 printAttribute(attr.getValue());
2880 }
2881
2882 void AsmPrinter::Impl::printDialectAttribute(Attribute attr) {
2883 auto &dialect = attr.getDialect();
2884
2885 // Ask the dialect to serialize the attribute to a string.
2886 std::string attrName;
2887 {
2888 llvm::raw_string_ostream attrNameStr(attrName);
2889 Impl subPrinter(attrNameStr, state);
2890 DialectAsmPrinter printer(subPrinter);
2891 dialect.printAttribute(attr, printer);
2892 }
2893 printDialectSymbol(os, "#", dialect.getNamespace(), attrName);
2894 }
2895
2896 void AsmPrinter::Impl::printDialectType(Type type) {
2897 auto &dialect = type.getDialect();
2898
2899 // Ask the dialect to serialize the type to a string.
2900 std::string typeName;
2901 {
2902 llvm::raw_string_ostream typeNameStr(typeName);
2903 Impl subPrinter(typeNameStr, state);
2904 DialectAsmPrinter printer(subPrinter);
2905 dialect.printType(type, printer);
2906 }
2907 printDialectSymbol(os, "!", dialect.getNamespace(), typeName);
2908 }
2909
2910 void AsmPrinter::Impl::printEscapedString(StringRef str) {
2911 os << "\"";
2912 llvm::printEscapedString(str, os);
2913 os << "\"";
2914 }
2915
2917 os << "\"0x" << llvm::toHex(str) << "\"";
2918 }
2920 printHexString(StringRef(data.data(), data.size()));
2921 }
2922
2924 return state.pushCyclicPrinting(opaquePointer);
2925 }
2926
2928
2931 }
2932
2933
2934
2935
2936
2938
2940 assert(impl && "expected AsmPrinter::getStream to be overriden");
2941 return impl->getStream();
2942 }
2943
2944
2946 assert(impl && "expected AsmPrinter::printFloat to be overriden");
2948 }
2949
2951 assert(impl && "expected AsmPrinter::printType to be overriden");
2952 impl->printType(type);
2953 }
2954
2956 assert(impl && "expected AsmPrinter::printAttribute to be overriden");
2957 impl->printAttribute(attr);
2958 }
2959
2961 assert(impl && "expected AsmPrinter::printAlias to be overriden");
2962 return impl->printAlias(attr);
2963 }
2964
2966 assert(impl && "expected AsmPrinter::printAlias to be overriden");
2967 return impl->printAlias(type);
2968 }
2969
2971 assert(impl &&
2972 "expected AsmPrinter::printAttributeWithoutType to be overriden");
2974 }
2975
2977 assert(impl && "expected AsmPrinter::printKeywordOrString to be overriden");
2979 }
2980
2982 assert(impl && "expected AsmPrinter::printString to be overriden");
2983 *this << '"';
2984 printEscapedString(keyword, getStream());
2985 *this << '"';
2986 }
2987
2989 assert(impl && "expected AsmPrinter::printSymbolName to be overriden");
2991 }
2992
2994 assert(impl && "expected AsmPrinter::printResourceHandle to be overriden");
2995 impl->printResourceHandle(resource);
2996 }
2997
3000 }
3001
3003 return impl->pushCyclicPrinting(opaquePointer);
3004 }
3005
3007
3008
3009
3010
3011
3014 printAffineExprInternal(expr, BindingStrength::Weak, printValueName);
3015 }
3016
3019 function_ref<void(unsigned, bool)> printValueName) {
3020 const char *binopSpelling = nullptr;
3021 switch (expr.getKind()) {
3023 unsigned pos = cast(expr).getPosition();
3024 if (printValueName)
3025 printValueName(pos, true);
3026 else
3027 os << 's' << pos;
3028 return;
3029 }
3031 unsigned pos = cast(expr).getPosition();
3032 if (printValueName)
3033 printValueName(pos, false);
3034 else
3035 os << 'd' << pos;
3036 return;
3037 }
3039 os << cast(expr).getValue();
3040 return;
3042 binopSpelling = " + ";
3043 break;
3045 binopSpelling = " * ";
3046 break;
3048 binopSpelling = " floordiv ";
3049 break;
3051 binopSpelling = " ceildiv ";
3052 break;
3054 binopSpelling = " mod ";
3055 break;
3056 }
3057
3058 auto binOp = cast(expr);
3059 AffineExpr lhsExpr = binOp.getLHS();
3060 AffineExpr rhsExpr = binOp.getRHS();
3061
3062
3064 if (enclosingTightness == BindingStrength::Strong)
3065 os << '(';
3066
3067
3068 auto rhsConst = dyn_cast(rhsExpr);
3070 rhsConst.getValue() == -1) {
3071 os << "-";
3072 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
3073 if (enclosingTightness == BindingStrength::Strong)
3074 os << ')';
3075 return;
3076 }
3077
3078 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
3079
3080 os << binopSpelling;
3081 printAffineExprInternal(rhsExpr, BindingStrength::Strong, printValueName);
3082
3083 if (enclosingTightness == BindingStrength::Strong)
3084 os << ')';
3085 return;
3086 }
3087
3088
3089 if (enclosingTightness == BindingStrength::Strong)
3090 os << '(';
3091
3092
3093
3094 if (auto rhs = dyn_cast(rhsExpr)) {
3097 if (auto rrhs = dyn_cast(rrhsExpr)) {
3098 if (rrhs.getValue() == -1) {
3099 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
3100 printValueName);
3101 os << " - ";
3103 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
3104 printValueName);
3105 } else {
3106 printAffineExprInternal(rhs.getLHS(), BindingStrength::Weak,
3107 printValueName);
3108 }
3109
3110 if (enclosingTightness == BindingStrength::Strong)
3111 os << ')';
3112 return;
3113 }
3114
3115 if (rrhs.getValue() < -1) {
3116 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
3117 printValueName);
3118 os << " - ";
3119 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
3120 printValueName);
3121 os << " * " << -rrhs.getValue();
3122 if (enclosingTightness == BindingStrength::Strong)
3123 os << ')';
3124 return;
3125 }
3126 }
3127 }
3128 }
3129
3130
3131 if (auto rhsConst = dyn_cast(rhsExpr)) {
3132 if (rhsConst.getValue() < 0) {
3133 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
3134 os << " - " << -rhsConst.getValue();
3135 if (enclosingTightness == BindingStrength::Strong)
3136 os << ')';
3137 return;
3138 }
3139 }
3140
3141 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
3142
3143 os << " + ";
3144 printAffineExprInternal(rhsExpr, BindingStrength::Weak, printValueName);
3145
3146 if (enclosingTightness == BindingStrength::Strong)
3147 os << ')';
3148 }
3149
3151 printAffineExprInternal(expr, BindingStrength::Weak);
3152 isEq ? os << " == 0" : os << " >= 0";
3153 }
3154
3156
3157 os << '(';
3158 for (int i = 0; i < (int)map.getNumDims() - 1; ++i)
3159 os << 'd' << i << ", ";
3162 os << ')';
3163
3164
3166 os << '[';
3167 for (unsigned i = 0; i < map.getNumSymbols() - 1; ++i)
3168 os << 's' << i << ", ";
3171 os << ']';
3172 }
3173
3174
3175 os << " -> (";
3177 [&](AffineExpr expr) { printAffineExpr(expr); });
3178 os << ')';
3179 }
3180
3182
3183 os << '(';
3184 for (unsigned i = 1; i < set.getNumDims(); ++i)
3185 os << 'd' << i - 1 << ", ";
3188 os << ')';
3189
3190
3192 os << '[';
3193 for (unsigned i = 0; i < set.getNumSymbols() - 1; ++i)
3194 os << 's' << i << ", ";
3197 os << ']';
3198 }
3199
3200
3201 os << " : (";
3203 for (int i = 1; i < numConstraints; ++i) {
3204 printAffineConstraint(set.getConstraint(i - 1), set.isEq(i - 1));
3205 os << ", ";
3206 }
3207 if (numConstraints >= 1)
3208 printAffineConstraint(set.getConstraint(numConstraints - 1),
3209 set.isEq(numConstraints - 1));
3210 os << ')';
3211 }
3212
3213
3214
3215
3216
3217 namespace {
3218
3220 public:
3223
3224 explicit OperationPrinter(raw_ostream &os, AsmStateImpl &state)
3226
3227
3228 void printTopLevelOperation(Operation *op);
3229
3230
3231
3232 void printFullOpWithIndentAndLoc(Operation *op);
3233
3234
3235 void printFullOp(Operation *op);
3236
3237
3238 void printCustomOrGenericOp(Operation *op) override;
3239
3240 void printGenericOp(Operation *op, bool printOpName) override;
3241
3242
3243 void printBlockName(Block *block);
3244
3245
3246
3247
3248 void print(Block *block, bool printBlockArgs = true,
3249 bool printBlockTerminator = true);
3250
3251
3252 void printValueID(Value value, bool printResultNo = true,
3253 raw_ostream *streamOverride = nullptr) const;
3254
3255
3256 void printOperationID(Operation *op,
3257 raw_ostream *streamOverride = nullptr) const;
3258
3259
3260
3261
3262
3263
3264
3265 void printOptionalLocationSpecifier(Location loc) override {
3266 printTrailingLocation(loc);
3267 }
3268
3269
3270
3272 os << newLine;
3273 os.indent(currentIndent);
3274 }
3275
3276
3277 void increaseIndent() override { currentIndent += indentWidth; }
3278
3279
3280 void decreaseIndent() override { currentIndent -= indentWidth; }
3281
3282
3283
3284
3285
3286
3289 bool omitType = false) override;
3290
3291
3292 void printOperand(Value value) override { printValueID(value); }
3293 void printOperand(Value value, raw_ostream &os) override {
3294 printValueID(value, true, &os);
3295 }
3296
3297
3301 }
3302 void printOptionalAttrDictWithKeyword(
3306 true);
3307 }
3308
3309
3310 void printSuccessor(Block *successor) override;
3311
3312
3313
3314 void printSuccessorAndUseList(Block *successor,
3316
3317
3319 bool printBlockTerminators, bool printEmptyBlock) override;
3320
3321
3322
3323
3324
3325 void shadowRegionArgs(Region ®ion, ValueRange namesToUse) override {
3326 state.getSSANameState().shadowRegionArgs(region, namesToUse);
3327 }
3328
3329
3330
3331 void printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3333
3334
3335
3338
3339
3340 void printUsersComment(Operation *op);
3341
3342
3344
3345
3346 void printValueUsers(Value value);
3347
3348
3349
3350 void printUserIDs(Operation *user, bool prefixComma = false);
3351
3352 private:
3353
3354
3356 public:
3357 using ValueFn = function_ref<void(raw_ostream &)>;
3358 using PrintFn = function_ref<void(StringRef, ValueFn)>;
3359
3360 ResourceBuilder(PrintFn printFn) : printFn(printFn) {}
3361 ~ResourceBuilder() override = default;
3362
3363 void buildBool(StringRef key, bool data) final {
3364 printFn(key, [&](raw_ostream &os) { os << (data ? "true" : "false"); });
3365 }
3366
3367 void buildString(StringRef key, StringRef data) final {
3368 printFn(key, [&](raw_ostream &os) {
3369 os << "\"";
3370 llvm::printEscapedString(data, os);
3371 os << "\"";
3372 });
3373 }
3374
3376 uint32_t dataAlignment) final {
3377 printFn(key, [&](raw_ostream &os) {
3378
3379 llvm::support::ulittle32_t dataAlignmentLE(dataAlignment);
3380 os << "\"0x"
3381 << llvm::toHex(StringRef(reinterpret_cast<char *>(&dataAlignmentLE),
3382 sizeof(dataAlignment)))
3383 << llvm::toHex(StringRef(data.data(), data.size())) << "\"";
3384 });
3385 }
3386
3387 private:
3388 PrintFn printFn;
3389 };
3390
3391
3392 void printFileMetadataDictionary(Operation *op);
3393
3394
3395
3396
3397
3398 void printResourceFileMetadata(function_ref<void()> checkAddMetadataDict,
3400
3401
3402
3403
3404
3405
3407
3408
3409 const static unsigned indentWidth = 2;
3410
3411
3412 unsigned currentIndent = 0;
3413 };
3414 }
3415
3416 void OperationPrinter::printTopLevelOperation(Operation *op) {
3417
3418 state.getAliasState().printNonDeferredAliases(*this, newLine);
3419
3420
3421 printFullOpWithIndentAndLoc(op);
3422 os << newLine;
3423
3424
3425 state.getAliasState().printDeferredAliases(*this, newLine);
3426
3427
3428 printFileMetadataDictionary(op);
3429 }
3430
3431 void OperationPrinter::printFileMetadataDictionary(Operation *op) {
3432 bool sawMetadataEntry = false;
3433 auto checkAddMetadataDict = [&] {
3434 if (!std::exchange(sawMetadataEntry, true))
3435 os << newLine << "{-#" << newLine;
3436 };
3437
3438
3439 printResourceFileMetadata(checkAddMetadataDict, op);
3440
3441
3442 if (sawMetadataEntry)
3443 os << newLine << "#-}" << newLine;
3444 }
3445
3446 void OperationPrinter::printResourceFileMetadata(
3448
3449 bool hadResource = false;
3450 bool needResourceComma = false;
3451 bool needEntryComma = false;
3452 auto processProvider = [&](StringRef dictName, StringRef name, auto &provider,
3453 auto &&...providerArgs) {
3454 bool hadEntry = false;
3455 auto printFn = [&](StringRef key, ResourceBuilder::ValueFn valueFn) {
3456 checkAddMetadataDict();
3457
3458 std::string resourceStr;
3459 auto printResourceStr = [&](raw_ostream &os) { os << resourceStr; };
3460 std::optional<uint64_t> charLimit =
3462 if (charLimit.has_value()) {
3463
3464 if (charLimit.value() == 0)
3465 return;
3466
3467 llvm::raw_string_ostream ss(resourceStr);
3468 valueFn(ss);
3469
3470
3471 if (resourceStr.size() > charLimit.value())
3472 return;
3473
3474
3475 valueFn = printResourceStr;
3476 }
3477
3478
3479 if (!std::exchange(hadResource, true)) {
3480 if (needResourceComma)
3481 os << "," << newLine;
3482 os << " " << dictName << "_resources: {" << newLine;
3483 }
3484
3485 if (!std::exchange(hadEntry, true)) {
3486 if (needEntryComma)
3487 os << "," << newLine;
3488 os << " " << name << ": {" << newLine;
3489 } else {
3490 os << "," << newLine;
3491 }
3492 os << " ";
3494 os << ": ";
3495
3496 valueFn(os);
3497 };
3498 ResourceBuilder entryBuilder(printFn);
3499 provider.buildResources(op, providerArgs..., entryBuilder);
3500
3501 needEntryComma |= hadEntry;
3502 if (hadEntry)
3503 os << newLine << " }";
3504 };
3505
3506
3507
3509 auto &dialectResources = state.getDialectResources();
3510 StringRef name = interface.getDialect()->getNamespace();
3511 auto it = dialectResources.find(interface.getDialect());
3512 if (it != dialectResources.end())
3513 processProvider("dialect", name, interface, it->second);
3514 else
3515 processProvider("dialect", name, interface,
3517 }
3518 if (hadResource)
3519 os << newLine << " }";
3520
3521
3522
3523 needEntryComma = false;
3524 needResourceComma = hadResource;
3525 hadResource = false;
3526 for (const auto &printer : state.getResourcePrinters())
3527 processProvider("external", printer.getName(), printer);
3528 if (hadResource)
3529 os << newLine << " }";
3530 }
3531
3532
3533
3534
3535
3536
3537 void OperationPrinter::printRegionArgument(BlockArgument arg,
3539 bool omitType) {
3540 printOperand(arg);
3541 if (!omitType) {
3542 os << ": ";
3544 }
3545 printOptionalAttrDict(argAttrs);
3546
3547 printTrailingLocation(arg.getLoc(), false);
3548 }
3549
3550 void OperationPrinter::printFullOpWithIndentAndLoc(Operation *op) {
3551
3552 state.registerOperationLocation(op, newLine.curLine, currentIndent);
3553
3554 os.indent(currentIndent);
3555 printFullOp(op);
3556 printTrailingLocation(op->getLoc());
3558 printUsersComment(op);
3559 }
3560
3561 void OperationPrinter::printFullOp(Operation *op) {
3563 auto printResultGroup = [&](size_t resultNo, size_t resultCount) {
3564 printValueID(op->getResult(resultNo), false);
3565 if (resultCount > 1)
3566 os << ':' << resultCount;
3567 };
3568
3569
3570 ArrayRef resultGroups = state.getSSANameState().getOpResultGroups(op);
3571 if (!resultGroups.empty()) {
3572
3573
3574 interleaveComma(llvm::seq(0, resultGroups.size() - 1), [&](int i) {
3575 printResultGroup(resultGroups[i],
3576 resultGroups[i + 1] - resultGroups[i]);
3577 });
3578 os << ", ";
3579 printResultGroup(resultGroups.back(), numResults - resultGroups.back());
3580
3581 } else {
3582 printResultGroup(0, numResults);
3583 }
3584
3585 os << " = ";
3586 }
3587
3588 printCustomOrGenericOp(op);
3589 }
3590
3591 void OperationPrinter::printUsersComment(Operation *op) {
3594 os << " // id: ";
3595 printOperationID(op);
3596 } else if (numResults && op->use_empty()) {
3597 os << " // unused";
3598 } else if (numResults && !op->use_empty()) {
3599
3600
3601 unsigned usedInNResults = 0;
3602 unsigned usedInNOperations = 0;
3605 if (userSet.insert(user).second) {
3606 ++usedInNOperations;
3607 usedInNResults += user->getNumResults();
3608 }
3609 }
3610
3611
3612 bool exactlyOneUniqueUse =
3613 usedInNResults <= 1 && usedInNOperations <= 1 && numResults == 1;
3614 os << " // " << (exactlyOneUniqueUse ? "user" : "users") << ": ";
3615 bool shouldPrintBrackets = numResults > 1;
3616 auto printOpResult = [&](OpResult opResult) {
3617 if (shouldPrintBrackets)
3618 os << "(";
3619 printValueUsers(opResult);
3620 if (shouldPrintBrackets)
3621 os << ")";
3622 };
3623
3624 interleaveComma(op->getResults(), printOpResult);
3625 }
3626 }
3627
3628 void OperationPrinter::printUsersComment(BlockArgument arg) {
3629 os << "// ";
3630 printValueID(arg);
3632 os << " is unused";
3633 } else {
3634 os << " is used by ";
3635 printValueUsers(arg);
3636 }
3637 os << newLine;
3638 }
3639
3640 void OperationPrinter::printValueUsers(Value value) {
3642 os << "unused";
3643
3644
3645
3648 if (userSet.insert(user).second)
3649 printUserIDs(user, index);
3650 }
3651 }
3652
3653 void OperationPrinter::printUserIDs(Operation *user, bool prefixComma) {
3654 if (prefixComma)
3655 os << ", ";
3656
3658 printOperationID(user);
3659 } else {
3661 [this](Value result) { printValueID(result); });
3662 }
3663 }
3664
3665 void OperationPrinter::printCustomOrGenericOp(Operation *op) {
3666
3668
3669
3671 opInfo->printAssembly(op, *this, defaultDialectStack.back());
3672 return;
3673 }
3674
3676 if (auto opPrinter = dialect->getOperationPrinter(op)) {
3677
3679
3680
3681 if (name.count('.') == 1)
3682 name.consume_front((defaultDialectStack.back() + ".").str());
3683 os << name;
3684
3685
3686 opPrinter(op, *this);
3687 return;
3688 }
3689 }
3690 }
3691
3692
3693 printGenericOp(op, true);
3694 }
3695
3696 void OperationPrinter::printGenericOp(Operation *op, bool printOpName) {
3697 if (printOpName)
3699 os << '(';
3700 interleaveComma(op->getOperands(), [&](Value value) { printValueID(value); });
3701 os << ')';
3702
3703
3705 os << '[';
3707 [&](Block *successor) { printBlockName(successor); });
3708 os << ']';
3709 }
3710
3711
3713 os << " <";
3715 os << '>';
3716 }
3717
3718 // Print regions.
3719 if (op->getNumRegions() != 0) {
3720 os << " (";
3721 interleaveComma(op->getRegions(), [&](Region ®ion) {
3722 printRegion(region, /*printEntryBlockArgs=*/true,
3723 /*printBlockTerminators=*/true, /*printEmptyBlock=*/true);
3724 });
3725 os << ')';
3726 }
3727
3728 printOptionalAttrDict(op->getPropertiesStorage()
3729 ? llvm::to_vector(op->getDiscardableAttrs())
3730 : op->getAttrs());
3731
3732 // Print the type signature of the operation.
3733 os << " : ";
3734 printFunctionalType(op);
3735 }
3736
3737 void OperationPrinter::printBlockName(Block *block) {
3738 os << state.getSSANameState().getBlockInfo(block).name;
3739 }
3740
3741 void OperationPrinter::print(Block *block, bool printBlockArgs,
3742 bool printBlockTerminator) {
3743 // Print the block label and argument list if requested.
3744 if (printBlockArgs) {
3745 os.indent(currentIndent);
3746 printBlockName(block);
3747
3748 // Print the argument list if non-empty.
3749 if (!block->args_empty()) {
3750 os << '(';
3751 interleaveComma(block->getArguments(), [&](BlockArgument arg) {
3752 printValueID(arg);
3753 os << ": ";
3754 printType(arg.getType());
3755 // TODO: We should allow location aliases on block arguments.
3756 printTrailingLocation(arg.getLoc(), /*allowAlias*/ false);
3757 });
3758 os << ')';
3759 }
3760 os << ':';
3761
3762 // Print out some context information about the predecessors of this block.
3763 if (!block->getParent()) {
3764 os << " // block is not in a region!";
3765 } else if (block->hasNoPredecessors()) {
3766 if (!block->isEntryBlock())
3767 os << " // no predecessors";
3768 } else if (auto *pred = block->getSinglePredecessor()) {
3769 os << " // pred: ";
3770 printBlockName(pred);
3771 } else {
3772 // We want to print the predecessors in a stable order, not in
3773 // whatever order the use-list is in, so gather and sort them.
3774 SmallVector<BlockInfo, 4> predIDs;
3775 for (auto *pred : block->getPredecessors())
3776 predIDs.push_back(state.getSSANameState().getBlockInfo(pred));
3777 llvm::sort(predIDs, [](BlockInfo lhs, BlockInfo rhs) {
3778 return lhs.ordering < rhs.ordering;
3779 });
3780
3781 os << " // " << predIDs.size() << " preds: ";
3782
3783 interleaveComma(predIDs, [&](BlockInfo pred) { os << pred.name; });
3784 }
3785 os << newLine;
3786 }
3787
3788 currentIndent += indentWidth;
3789
3790 if (printerFlags.shouldPrintValueUsers()) {
3791 for (BlockArgument arg : block->getArguments()) {
3792 os.indent(currentIndent);
3793 printUsersComment(arg);
3794 }
3795 }
3796
3797 bool hasTerminator =
3798 !block->empty() && block->back().hasTraitOpTrait::IsTerminator();
3799 auto range = llvm::make_range(
3800 block->begin(),
3801 std::prev(block->end(),
3802 (!hasTerminator || printBlockTerminator) ? 0 : 1));
3803 for (auto &op : range) {
3804 printFullOpWithIndentAndLoc(&op);
3805 os << newLine;
3806 }
3807 currentIndent -= indentWidth;
3808 }
3809
3810 void OperationPrinter::printValueID(Value value, bool printResultNo,
3811 raw_ostream *streamOverride) const {
3812 state.getSSANameState().printValueID(value, printResultNo,
3813 streamOverride ? *streamOverride : os);
3814 }
3815
3816 void OperationPrinter::printOperationID(Operation *op,
3817 raw_ostream *streamOverride) const {
3818 state.getSSANameState().printOperationID(op, streamOverride ? *streamOverride
3819 : os);
3820 }
3821
3822 void OperationPrinter::printSuccessor(Block *successor) {
3823 printBlockName(successor);
3824 }
3825
3826 void OperationPrinter::printSuccessorAndUseList(Block *successor,
3827 ValueRange succOperands) {
3828 printBlockName(successor);
3829 if (succOperands.empty())
3830 return;
3831
3832 os << '(';
3833 interleaveComma(succOperands,
3834 [this](Value operand) { printValueID(operand); });
3835 os << " : ";
3836 interleaveComma(succOperands,
3837 [this](Value operand) { printType(operand.getType()); });
3838 os << ')';
3839 }
3840
3841 void OperationPrinter::printRegion(Region ®ion, bool printEntryBlockArgs,
3842 bool printBlockTerminators,
3843 bool printEmptyBlock) {
3844 if (printerFlags.shouldSkipRegions()) {
3845 os << "{...}";
3846 return;
3847 }
3848 os << "{" << newLine;
3849 if (!region.empty()) {
3850 auto restoreDefaultDialect =
3851 llvm::make_scope_exit([&]() { defaultDialectStack.pop_back(); });
3852 if (auto iface = dyn_cast(region.getParentOp()))
3853 defaultDialectStack.push_back(iface.getDefaultDialect());
3854 else
3855 defaultDialectStack.push_back("");
3856
3857 auto *entryBlock = ®ion.front();
3858 // Force printing the block header if printEmptyBlock is set and the block
3859 // is empty or if printEntryBlockArgs is set and there are arguments to
3860 // print.
3861 bool shouldAlwaysPrintBlockHeader =
3862 (printEmptyBlock && entryBlock->empty()) ||
3863 (printEntryBlockArgs && entryBlock->getNumArguments() != 0);
3864 print(entryBlock, shouldAlwaysPrintBlockHeader, printBlockTerminators);
3865 for (auto &b : llvm::drop_begin(region.getBlocks(), 1))
3866 print(&b);
3867 }
3868 os.indent(currentIndent) << "}";
3869 }
3870
3871 void OperationPrinter::printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3872 ValueRange operands) {
3873 if (!mapAttr) {
3874 os << "<>";
3875 return;
3876 }
3877 AffineMap map = mapAttr.getValue();
3878 unsigned numDims = map.getNumDims();
3879 auto printValueName = [&](unsigned pos, bool isSymbol) {
3880 unsigned index = isSymbol ? numDims + pos : pos;
3881 assert(index < operands.size());
3882 if (isSymbol)
3883 os << "symbol(";
3884 printValueID(operands[index]);
3885 if (isSymbol)
3886 os << ')';
3887 };
3888
3889 interleaveComma(map.getResults(), [&](AffineExpr expr) {
3890 printAffineExpr(expr, printValueName);
3891 });
3892 }
3893
3894 void OperationPrinter::printAffineExprOfSSAIds(AffineExpr expr,
3895 ValueRange dimOperands,
3896 ValueRange symOperands) {
3897 auto printValueName = [&](unsigned pos, bool isSymbol) {
3898 if (!isSymbol)
3899 return printValueID(dimOperands[pos]);
3900 os << "symbol(";
3901 printValueID(symOperands[pos]);
3902 os << ')';
3903 };
3904 printAffineExpr(expr, printValueName);
3905 }
3906
3907 //===----------------------------------------------------------------------===//
3908 // print and dump methods
3909 //===----------------------------------------------------------------------===//
3910
3911 void Attribute::print(raw_ostream &os, bool elideType) const {
3912 if (!*this) {
3913 os << "<>";
3914 return;
3915 }
3916
3917 AsmState state(getContext());
3918 print(os, state, elideType);
3919 }
3920 void Attribute::print(raw_ostream &os, AsmState &state, bool elideType) const {
3921 using AttrTypeElision = AsmPrinter::Impl::AttrTypeElision;
3922 AsmPrinter::Impl(os, state.getImpl())
3923 .printAttribute(*this, elideType ? AttrTypeElision::Must
3924 : AttrTypeElision::Never);
3925 }
3926
3927 void Attribute::dump() const {
3928 print(llvm::errs());
3929 llvm::errs() << "\n";
3930 }
3931
3932 void Attribute::printStripped(raw_ostream &os, AsmState &state) const {
3933 if (!*this) {
3934 os << "<>";
3935 return;
3936 }
3937
3938 AsmPrinter::Impl subPrinter(os, state.getImpl());
3939 if (succeeded(subPrinter.printAlias(*this)))
3940 return;
3941
3942 auto &dialect = this->getDialect();
3943 uint64_t posPrior = os.tell();
3944 DialectAsmPrinter printer(subPrinter);
3945 dialect.printAttribute(*this, printer);
3946 if (posPrior != os.tell())
3947 return;
3948
3949 // Fallback to printing with prefix if the above failed to write anything
3950 // to the output stream.
3951 print(os, state);
3952 }
3953 void Attribute::printStripped(raw_ostream &os) const {
3954 if (!*this) {
3955 os << "<>";
3956 return;
3957 }
3958
3959 AsmState state(getContext());
3960 printStripped(os, state);
3961 }
3962
3963 void Type::print(raw_ostream &os) const {
3964 if (!*this) {
3965 os << "<>";
3966 return;
3967 }
3968
3969 AsmState state(getContext());
3970 print(os, state);
3971 }
3972 void Type::print(raw_ostream &os, AsmState &state) const {
3973 AsmPrinter::Impl(os, state.getImpl()).printType(*this);
3974 }
3975
3976 void Type::dump() const {
3977 print(llvm::errs());
3978 llvm::errs() << "\n";
3979 }
3980
3981 void AffineMap::dump() const {
3982 print(llvm::errs());
3983 llvm::errs() << "\n";
3984 }
3985
3986 void IntegerSet::dump() const {
3987 print(llvm::errs());
3988 llvm::errs() << "\n";
3989 }
3990
3991 void AffineExpr::print(raw_ostream &os) const {
3992 if (!expr) {
3993 os << "<>";
3994 return;
3995 }
3996 AsmState state(getContext());
3997 AsmPrinter::Impl(os, state.getImpl()).printAffineExpr(*this);
3998 }
3999
4000 void AffineExpr::dump() const {
4001 print(llvm::errs());
4002 llvm::errs() << "\n";
4003 }
4004
4005 void AffineMap::print(raw_ostream &os) const {
4006 if (!map) {
4007 os << "<>";
4008 return;
4009 }
4010 AsmState state(getContext());
4011 AsmPrinter::Impl(os, state.getImpl()).printAffineMap(*this);
4012 }
4013
4014 void IntegerSet::print(raw_ostream &os) const {
4015 AsmState state(getContext());
4016 AsmPrinter::Impl(os, state.getImpl()).printIntegerSet(*this);
4017 }
4018
4019 void Value::print(raw_ostream &os) const { print(os, OpPrintingFlags()); }
4020 void Value::print(raw_ostream &os, const OpPrintingFlags &flags) const {
4021 if (!impl) {
4022 os << "<>";
4023 return;
4024 }
4025
4026 if (auto *op = getDefiningOp())
4027 return op->print(os, flags);
4028 // TODO: Improve BlockArgument print'ing.
4029 BlockArgument arg = llvm::cast(*this);
4030 os << " of type '" << arg.getType()
4032 }
4034 if () {
4035 os << "<>";
4036 return;
4037 }
4038
4039 if (auto *op = getDefiningOp())
4040 return op->print(os, state);
4041
4042
4043 BlockArgument arg = llvm::cast(*this);
4044 os << " of type '" << arg.getType()
4046 }
4047
4049 print(llvm::errs());
4050 llvm::errs() << "\n";
4051 }
4052
4054
4055
4056
4057
4058 state.getImpl().getSSANameState().printValueID(*this, true,
4059 os);
4060 }
4061
4063 do {
4064
4065
4067 break;
4068
4069
4071 if (!parentOp)
4072 break;
4073 op = parentOp;
4074 } while (true);
4075 return op;
4076 }
4077
4081 if (auto result = llvm::dyn_cast(*this)) {
4083 } else {
4084 op = llvm::cast(*this).getOwner()->getParentOp();
4085 if (!op) {
4086 os << "<>";
4087 return;
4088 }
4089 }
4092 printAsOperand(os, state);
4093 }
4094
4096
4098 AsmState state(op, printerFlags);
4099 print(os, state);
4100 }
4102 OperationPrinter printer(os, state.getImpl());
4103 if (!getParent() && !state.getPrinterFlags().shouldUseLocalScope()) {
4104 state.getImpl().initializeAliases(this);
4105 printer.printTopLevelOperation(this);
4106 } else {
4107 printer.printFullOpWithIndentAndLoc(this);
4108 }
4109 }
4110
4113 llvm::errs() << "\n";
4114 }
4115
4118 llvm::errs() << "\n";
4119 }
4120
4122 Operation *parentOp = getParentOp();
4123 if (!parentOp) {
4124 os << "<>\n";
4125 return;
4126 }
4127
4128 while (auto *nextOp = parentOp->getParentOp())
4129 parentOp = nextOp;
4130
4132 print(os, state);
4133 }
4135 OperationPrinter(os, state.getImpl()).print(this);
4136 }
4137
4139
4140
4142 Operation *parentOp = getParentOp();
4143 if (!parentOp) {
4144 os << "<>\n";
4145 return;
4146 }
4148 printAsOperand(os, state);
4149 }
4151 OperationPrinter printer(os, state.getImpl());
4152 printer.printBlockName(this);
4153 }
4154
4156 block.print(os);
4157 return os;
4158 }
4159
4160
4161
4162
4163 namespace mlir {
4164
4167 if (dimensions.empty())
4168 printer << "[";
4170 if (dimensions.empty())
4171 printer << "]";
4172 }
4173
4176
4180 << "Failed parsing dimension list.";
4181 }
4182 dimensions =
4184 return success();
4185 }
4186
4187
4191 << "Failed parsing dimension list.";
4192 }
4193 if (shapeArr.empty()) {
4195 << "Failed parsing dimension list. Did you mean an empty list? It "
4196 "must be denoted by \"[]\".";
4197 }
4199 return success();
4200 }
4201
4202 }
static void printSymbolReference(StringRef symbolRef, raw_ostream &os)
Print the given string as a symbol reference.
static void printFloatValue(const APFloat &apValue, raw_ostream &os, bool *printedHex=nullptr)
Print a floating point value in a way that the parser will be able to round-trip losslessly.
static StringRef sanitizeIdentifier(StringRef name, SmallString< 16 > &buffer, StringRef allowedPunctChars="$._-")
Sanitize the given name such that it can be used as a valid identifier.
static llvm::ManagedStatic< AsmPrinterOptions > clOptions
static Operation * findParent(Operation *op, bool shouldUseLocalScope)
static void printKeywordOrString(StringRef keyword, raw_ostream &os)
Print the given string as a keyword, or a quoted and escaped string if it has any special or non-prin...
static bool isDialectSymbolSimpleEnoughForPrettyForm(StringRef symName)
Returns true if the given dialect symbol data is simple enough to print in the pretty form.
static void printDialectSymbol(raw_ostream &os, StringRef symPrefix, StringRef dialectName, StringRef symString)
Print the given dialect symbol to the stream.
static OpPrintingFlags verifyOpAndAdjustFlags(Operation *op, OpPrintingFlags printerFlags)
Verifies the operation and switches to generic op printing if verification fails.
MLIR_CRUNNERUTILS_EXPORT void printString(char const *s)
MLIR_CRUNNERUTILS_EXPORT void printNewline()
static void visit(Operation *op, DenseSet< Operation * > &visited)
Visits all the pdl.operand(s), pdl.result(s), and pdl.operation(s) connected to the given operation.
static MLIRContext * getContext(OpFoldResult val)
union mlir::linalg::@1203::ArityGroupAndKind::Kind kind
static std::string diag(const llvm::Value &value)
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
static void printRegion(llvm::raw_ostream &os, Region *region, OpPrintingFlags &flags)
Base type for affine expression.
AffineExprKind getKind() const
Return the classification for this type.
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
unsigned getNumSymbols() const
unsigned getNumDims() const
ArrayRef< AffineExpr > getResults() const
This class represents an opaque handle to a dialect resource entry.
This class represents a single parsed resource entry.
virtual FailureOr< AsmResourceBlob > parseAsBlob(BlobAllocatorFn allocator) const =0
Parse the resource entry represented by a binary blob.
virtual InFlightDiagnostic emitError() const =0
Emit an error at the location of this entry.
virtual AsmResourceEntryKind getKind() const =0
Return the kind of this value.
virtual FailureOr< std::string > parseAsString() const =0
Parse the resource entry represented by a human-readable string.
virtual FailureOr< bool > parseAsBool() const =0
Parse the resource entry represented by a boolean.
virtual StringRef getKey() const =0
Return the key of the resource entry.
MLIRContext * getContext() const
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
virtual ParseResult parseRSquare()=0
Parse a ] token.
virtual ParseResult parseDimensionList(SmallVectorImpl< int64_t > &dimensions, bool allowDynamic=true, bool withTrailingX=true)=0
Parse a dimension list of a tensor or memref type.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
ParseResult parseTypeList(SmallVectorImpl< Type > &result)
Parse a type list.
virtual ParseResult parseOptionalLSquare()=0
Parse a [ token if present.
Impl(raw_ostream &os, AsmStateImpl &state)
BindingStrength
This enum is used to represent the binding strength of the enclosing context that an AffineExprStorag...
void printHexString(StringRef str)
Print a hex string, wrapped with "".
void printDenseArrayAttr(DenseArrayAttr attr)
Print a dense array attribute.
void printDenseElementsAttr(DenseElementsAttr attr, bool allowHex)
Print a dense elements attribute.
void printAttribute(Attribute attr, AttrTypeElision typeElision=AttrTypeElision::Never)
Print the given attribute or an alias.
void printDimensionList(ArrayRef< int64_t > shape)
OpPrintingFlags printerFlags
A set of flags to control the printer's behavior.
raw_ostream & os
The output stream for the printer.
void printResourceHandle(const AsmDialectResourceHandle &resource)
Print a reference to the given resource that is owned by the given dialect.
raw_ostream & getStream()
Returns the output stream of the printer.
LogicalResult printAlias(Attribute attr)
Print the alias for the given attribute, return failure if no alias could be printed.
void printDialectAttribute(Attribute attr)
void interleaveComma(const Container &c, UnaryFunctor eachFn) const
void printDialectType(Type type)
void printLocation(LocationAttr loc, bool allowAlias=false)
Print the given location to the stream.
AsmStateImpl & state
An underlying assembly printer state.
void printAffineMap(AffineMap map)
void printTrailingLocation(Location loc, bool allowAlias=true)
void printAffineExprInternal(AffineExpr expr, BindingStrength enclosingTightness, function_ref< void(unsigned, bool)> printValueName=nullptr)
void printEscapedString(StringRef str)
Print an escaped string, wrapped with "".
void printAffineExpr(AffineExpr expr, function_ref< void(unsigned, bool)> printValueName=nullptr)
void printDenseStringElementsAttr(DenseStringElementsAttr attr)
Print a dense string elements attribute.
void printAttributeImpl(Attribute attr, AttrTypeElision typeElision=AttrTypeElision::Never)
Print the given attribute without considering an alias.
void printAffineConstraint(AffineExpr expr, bool isEq)
void printDenseIntOrFPElementsAttr(DenseIntOrFPElementsAttr attr, bool allowHex)
Print a dense elements attribute.
AttrTypeElision
This enum describes the different kinds of elision for the type of an attribute when printing it.
@ May
The type may be elided when it matches the default used in the parser (for example i64 is the default...
@ Never
The type must not be elided,.
@ Must
The type must be elided.
LogicalResult pushCyclicPrinting(const void *opaquePointer)
void printIntegerSet(IntegerSet set)
NewLineCounter newLine
A tracker for the number of new lines emitted during printing.
void printOptionalAttrDict(ArrayRef< NamedAttribute > attrs, ArrayRef< StringRef > elidedAttrs={}, bool withKeyword=false)
void printType(Type type)
Print the given type or an alias.
void printLocationInternal(LocationAttr loc, bool pretty=false, bool isTopLevel=false)
void printTypeImpl(Type type)
Print the given type.
void printNamedAttribute(NamedAttribute attr)
virtual void printAttributeWithoutType(Attribute attr)
Print the given attribute without its type.
virtual LogicalResult printAlias(Attribute attr)
Print the alias for the given attribute, return failure if no alias could be printed.
virtual void popCyclicPrinting()
Removes the element that was last inserted with a successful call to pushCyclicPrinting.
virtual LogicalResult pushCyclicPrinting(const void *opaquePointer)
Pushes a new attribute or type in the form of a type erased pointer into an internal set.
virtual void printType(Type type)
virtual void printKeywordOrString(StringRef keyword)
Print the given string as a keyword, or a quoted and escaped string if it has any special or non-prin...
virtual void printSymbolName(StringRef symbolRef)
Print the given string as a symbol reference, i.e.
virtual void printString(StringRef string)
Print the given string as a quoted string, escaping any special or non-printable characters in it.
virtual void printAttribute(Attribute attr)
void printDimensionList(ArrayRef< int64_t > shape)
virtual raw_ostream & getStream() const
Return the raw output stream used by this printer.
virtual void printResourceHandle(const AsmDialectResourceHandle &resource)
Print a handle to the given dialect resource.
virtual void printFloat(const APFloat &value)
Print the given floating point value in a stabilized form that can be roundtripped through the IR.
This class is used to build resource entries for use by the printer.
virtual void buildString(StringRef key, StringRef data)=0
Build a resource entry represented by the given human-readable string value.
virtual void buildBool(StringRef key, bool data)=0
Build a resource entry represented by the given bool.
virtual void buildBlob(StringRef key, ArrayRef< char > data, uint32_t dataAlignment)=0
Build an resource entry represented by the given binary blob data.
This class represents an instance of a resource parser.
static std::unique_ptr< AsmResourcePrinter > fromCallable(StringRef name, CallableT &&printFn)
Return a resource printer implemented via the given callable, whose form should match that of buildRe...
This class provides management for the lifetime of the state used when printing the IR.
void attachResourcePrinter(std::unique_ptr< AsmResourcePrinter > printer)
Attach the given resource printer to the AsmState.
DenseMap< Dialect *, SetVector< AsmDialectResourceHandle > > & getDialectResources() const
Returns a map of dialect resources that were referenced when using this state to print IR.
void attachFallbackResourcePrinter(FallbackAsmResourceMap &map)
Attach resource printers to the AsmState for the fallback resources in the given map.
const OpPrintingFlags & getPrinterFlags() const
Get the printer flags.
Attributes are known-constant values of operations.
Dialect & getDialect() const
Get the dialect this attribute is registered to.
bool hasTrait()
Returns true if the type was registered with a particular trait.
const void * getAsOpaquePointer() const
Get an opaque pointer to the attribute.
static Attribute getFromOpaquePointer(const void *ptr)
Construct an attribute from the opaque pointer representation.
This class represents an argument of a Block.
Location getLoc() const
Return the location for this argument.
unsigned getArgNumber() const
Returns the number of this argument.
Block represents an ordered list of Operations.
void printAsOperand(raw_ostream &os, bool printType=true)
Print out the name of the block without printing its body.
void print(raw_ostream &os)
BlockArgListType getArguments()
bool isEntryBlock()
Return if this block is the entry block in the parent region.
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
An attribute that represents a reference to a dense vector or tensor object.
This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine.
~DialectAsmParser() override
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
~DialectAsmPrinter() override
A collection of dialect interfaces within a context, for a given concrete interface type.
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
virtual void printAttribute(Attribute, DialectAsmPrinter &) const
Print an attribute registered to this dialect.
virtual void printType(Type, DialectAsmPrinter &) const
Print a type registered to this dialect.
An attribute that associates a referenced attribute with a unique identifier.
A fallback map containing external resources not explicitly handled by another parser/printer.
std::vector< std::unique_ptr< AsmResourcePrinter > > getPrinters()
Build a set of resource printers to print the resources within this map.
An integer set representing a conjunction of one or more affine equalities and inequalities.
unsigned getNumDims() const
unsigned getNumConstraints() const
AffineExpr getConstraint(unsigned idx) const
bool isEq(unsigned idx) const
Returns true if the idx^th constraint is an equality, false if it is an inequality.
unsigned getNumSymbols() const
Location objects represent source locations information in MLIR.
T findInstanceOf()
Return an instance of the given location type if one is nested under the current location.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
NamedAttribute represents a combination of a name and an Attribute value.
Attribute getValue() const
Return the value of the attribute.
virtual LogicalResult parseResource(AsmParsedResourceEntry &entry) const
Hook for parsing resource entries.
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
void printFunctionalType(Operation *op)
Print the complete type of an operation in functional form.
Set of flags used to control the behavior of the various IR print methods (e.g.
bool shouldElideElementsAttr(ElementsAttr attr) const
Return if the given ElementsAttr should be elided.
std::optional< int64_t > getLargeElementsAttrLimit() const
Return the size limit for printing large ElementsAttr.
bool shouldUseNameLocAsPrefix() const
Return if the printer should use NameLocs as prefixes when printing SSA IDs.
bool shouldAssumeVerified() const
Return if operation verification should be skipped.
OpPrintingFlags & printLargeElementsAttrWithHex(int64_t largeElementLimit=100)
Enables the printing of large element attributes with a hex string.
bool shouldUseLocalScope() const
Return if the printer should use local scope when dumping the IR.
bool shouldPrintDebugInfoPrettyForm() const
Return if debug information should be printed in the pretty form.
bool shouldPrintElementsAttrWithHex(ElementsAttr attr) const
Return if the given ElementsAttr should be printed as hex string.
bool shouldPrintUniqueSSAIDs() const
Return if printer should use unique SSA IDs.
bool shouldPrintValueUsers() const
Return if the printer should print users of values.
int64_t getLargeElementsAttrHexLimit() const
Return the size limit for printing large ElementsAttr as hex string.
bool shouldPrintGenericOpForm() const
Return if operations should be printed in the generic form.
OpPrintingFlags & elideLargeResourceString(int64_t largeResourceLimit=64)
Enables the elision of large resources strings by omitting them from the dialect_resources section.
bool shouldPrintDebugInfo() const
Return if debug information should be printed.
OpPrintingFlags & elideLargeElementsAttrs(int64_t largeElementLimit=16)
Enables the elision of large elements attributes by printing a lexically valid but otherwise meaningl...
OpPrintingFlags & printNameLocAsPrefix(bool enable=true)
Print SSA IDs using their NameLoc, if provided, as prefix.
OpPrintingFlags & printValueUsers(bool enable=true)
Print users of values as comments.
OpPrintingFlags & enableDebugInfo(bool enable=true, bool prettyForm=false)
Enable or disable printing of debug information (based on enable).
OpPrintingFlags()
Initialize the printing flags with default supplied by the cl::opts above.
bool shouldSkipRegions() const
Return if regions should be skipped.
OpPrintingFlags & printGenericOpForm(bool enable=true)
Always print operations in the generic form.
OpPrintingFlags & useLocalScope(bool enable=true)
Use local scope when printing the operation.
std::optional< uint64_t > getLargeResourceStringLimit() const
Return the size limit in chars for printing large resources.
OpPrintingFlags & assumeVerified(bool enable=true)
Do not verify the operation when using custom operation printers.
OpPrintingFlags & skipRegions(bool skip=true)
Skip printing regions.
OpPrintingFlags & printUniqueSSAIDs(bool enable=true)
Print unique SSA ID numbers for values, block arguments and naming conflicts across all regions.
This is a value defined by a result of an operation.
Operation * getOwner() const
Returns the operation that owns this result.
unsigned getResultNumber() const
Returns the number of this result.
This class provides the API for ops that are known to be isolated from above.
This class provides the API for ops that are known to be terminators.
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
void printAssembly(Operation *op, OpAsmPrinter &p, StringRef defaultDialect) const
This hook implements the AsmPrinter for this operation.
void print(raw_ostream &os) const
Operation is the basic unit of execution within MLIR.
bool use_empty()
Returns true if this operation has no uses.
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
Dialect * getDialect()
Return the dialect this operation is associated with, or nullptr if the associated dialect is not loa...
unsigned getNumSuccessors()
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
void print(raw_ostream &os, const OpPrintingFlags &flags=std::nullopt)
MLIRContext * getContext()
Return the context this operation is associated with.
std::optional< RegisteredOperationName > getRegisteredInfo()
If this operation has a registered operation description, return it.
Location getLoc()
The source location the operation was defined or derived from.
unsigned getNumOperands()
Attribute getPropertiesAsAttribute()
Return the properties converted to an attribute.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
ArrayRef< NamedAttribute > getAttrs()
Return all of the attributes on this operation.
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
OperationName getName()
The name of an operation is the key identifier for it.
operand_type_range getOperandTypes()
result_type_range getResultTypes()
LLVM_DUMP_METHOD void dumpPretty()
operand_range getOperands()
Returns an iterator on the underlying Value's.
user_range getUsers()
Returns a range of all users.
SuccessorRange getSuccessors()
result_range getResults()
unsigned getNumResults()
Return the number of results held by this operation.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
iterator_range< OpIterator > getOps()
BlockArgListType getArguments()
Operation * getParentOp()
Return the parent operation this region is attached to.
unsigned getNumArguments()
BlockArgument getArgument(unsigned i)
This diagnostic handler is a simple RAII class that registers and erases a diagnostic handler on a gi...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
const void * getAsOpaquePointer() const
Methods for supporting PointerLikeTypeTraits.
Dialect & getDialect() const
Get the dialect this type is registered to.
static Type getFromOpaquePointer(const void *pointer)
void walkImmediateSubElements(function_ref< void(Attribute)> walkAttrsFn, function_ref< void(Type)> walkTypesFn) const
Walk all of the immediately nested sub-attributes and sub-types.
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
bool use_empty() const
Returns true if this value has no uses.
void print(raw_ostream &os) const
Type getType() const
Return the type of this value.
void printAsOperand(raw_ostream &os, AsmState &state) const
Print this value as if it were an operand.
user_range getUsers() const
Location getLoc() const
Return the location of this value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
void registerOperationLocation(Operation *op, unsigned line, unsigned col)
Register the location, line and column, within the buffer that the given operation was printed at.
const OpPrintingFlags & getPrinterFlags() const
Get the printer flags.
auto getResourcePrinters()
Return the non-dialect resource printers.
LogicalResult pushCyclicPrinting(const void *opaquePointer)
SSANameState & getSSANameState()
Get the state used for SSA names.
DialectInterfaceCollection< OpAsmDialectInterface > & getDialectInterfaces()
Return the dialects within the context that implement OpAsmDialectInterface.
AliasState & getAliasState()
Get the state used for aliases.
void initializeAliases(Operation *op)
Initialize the alias state to enable the printing of aliases.
AsmStateImpl(Operation *op, const OpPrintingFlags &printerFlags, AsmState::LocationMap *locationMap)
DenseMap< Dialect *, SetVector< AsmDialectResourceHandle > > & getDialectResources()
Return the referenced dialect resources within the printer.
AsmStateImpl(MLIRContext *ctx, const OpPrintingFlags &printerFlags, AsmState::LocationMap *locationMap)
DistinctState & getDistinctState()
Get the state used for distinct attribute identifiers.
Base class for DenseArrayAttr that is instantiated and specialized for each supported element type be...
static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef< T > content)
Builder from ArrayRef.
void printType(Type type, AsmPrinter &printer)
Prints an LLVM Dialect type.
LogicalResult parseCommaSeparatedList(llvm:🆑:Option &opt, StringRef argName, StringRef optionStr, function_ref< LogicalResult(StringRef)> elementParseFn)
Parse a string containing a list of comma-delimited elements, invoking the given parser for each sub-...
void printDimensionList(raw_ostream &stream, Range &&shape)
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
bool operator<(const Fraction &x, const Fraction &y)
Include the generated interface declarations.
ParseResult parseDimensionList(OpAsmParser &parser, DenseI64ArrayAttr &dimensions)
StringRef toString(AsmResourceEntryKind kind)
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
OpAsmAliasResult
Holds the result of OpAsm{Dialect,Attr,Type}Interface::getAlias hook call.
@ NoAlias
The object (type or attribute) is not supported by the hook and an alias was not provided.
@ CeilDiv
RHS of ceildiv is always a constant or a symbolic expression.
@ Mul
RHS of mul is always a constant or a symbolic expression.
@ Mod
RHS of mod is always a constant or a symbolic expression with a positive value.
@ DimId
Dimensional identifier.
@ FloorDiv
RHS of floordiv is always a constant or a symbolic expression.
@ Constant
Constant integer.
@ SymbolId
Symbolic identifier.
void registerAsmPrinterCLOptions()
Register a set of useful command-line options that can be used to configure various flags within the ...
Type parseType(llvm::StringRef typeStr, MLIRContext *context, size_t *numRead=nullptr, bool isKnownNullTerminated=false)
This parses a single MLIR type to an MLIR context if it was valid.
AsmResourceEntryKind
This enum represents the different kinds of resource values.
@ Blob
A blob of data with an accompanying alignment.
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
raw_ostream & operator<<(raw_ostream &os, const AliasResult &result)
Represents a range (offset, size, and stride) where each element of the triple may be dynamic or stat...
This trait is used to determine if a storage user, like Type, is mutable or not.