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>
59 #define DEBUG_TYPE "mlir-asm-printer"
80 [&]() {
return parseType(result.emplace_back()); });
96 auto &os = getStream();
100 *this << (operand ? operand.getType() : Type());
116 *this << (result ? result.getType() : Type());
128 #include "mlir/IR/OpAsmInterface.cpp.inc"
132 return entry.
emitError() <<
"unknown 'resource' key '" << entry.
getKey()
133 <<
"' for dialect '" << getDialect()->getNamespace()
145 struct AsmPrinterOptions {
146 llvm::cl::opt<int64_t> printElementsAttrWithHexIfLarger{
147 "mlir-print-elementsattrs-with-hex-if-larger",
149 "Print DenseElementsAttrs with a hex string that have "
150 "more elements than the given upper limit (use -1 to disable)")};
152 llvm::cl::opt<unsigned> elideElementsAttrIfLarger{
153 "mlir-elide-elementsattrs-if-larger",
154 llvm::cl::desc(
"Elide ElementsAttrs with \"...\" that have "
155 "more elements than the given upper limit")};
157 llvm::cl::opt<unsigned> elideResourceStringsIfLarger{
158 "mlir-elide-resource-strings-if-larger",
160 "Elide printing value of resources if string is too long in chars.")};
162 llvm::cl::opt<bool> printDebugInfoOpt{
163 "mlir-print-debuginfo", llvm::cl::init(
false),
164 llvm::cl::desc(
"Print debug info in MLIR output")};
166 llvm::cl::opt<bool> printPrettyDebugInfoOpt{
167 "mlir-pretty-debuginfo", llvm::cl::init(
false),
168 llvm::cl::desc(
"Print pretty debug info in MLIR output")};
172 llvm::cl::opt<bool> printGenericOpFormOpt{
173 "mlir-print-op-generic", llvm::cl::init(
false),
174 llvm::cl::desc(
"Print the generic op form"), llvm::cl::Hidden};
176 llvm::cl::opt<bool> assumeVerifiedOpt{
177 "mlir-print-assume-verified", llvm::cl::init(
false),
178 llvm::cl::desc(
"Skip op verification when using custom printers"),
181 llvm::cl::opt<bool> printLocalScopeOpt{
182 "mlir-print-local-scope", llvm::cl::init(
false),
183 llvm::cl::desc(
"Print with local scope and inline information (eliding "
184 "aliases for attributes, types, and locations")};
186 llvm::cl::opt<bool> skipRegionsOpt{
187 "mlir-print-skip-regions", llvm::cl::init(
false),
188 llvm::cl::desc(
"Skip regions when printing ops.")};
190 llvm::cl::opt<bool> printValueUsers{
191 "mlir-print-value-users", llvm::cl::init(
false),
193 "Print users of operation results and block arguments as a comment")};
195 llvm::cl::opt<bool> printUniqueSSAIDs{
196 "mlir-print-unique-ssa-ids", llvm::cl::init(
false),
197 llvm::cl::desc(
"Print unique SSA ID numbers for values, block arguments "
198 "and naming conflicts across all regions")};
200 llvm::cl::opt<bool> useNameLocAsPrefix{
201 "mlir-use-nameloc-as-prefix", llvm::cl::init(
false),
202 llvm::cl::desc(
"Print SSA IDs using NameLocs as prefixes")};
206 static llvm::ManagedStatic<AsmPrinterOptions>
clOptions;
217 : printDebugInfoFlag(false), printDebugInfoPrettyFormFlag(false),
218 printGenericOpFormFlag(false), skipRegionsFlag(false),
219 assumeVerifiedFlag(false), printLocalScope(false),
220 printValueUsersFlag(false), printUniqueSSAIDsFlag(false),
221 useNameLocAsPrefix(false) {
225 if (
clOptions->elideElementsAttrIfLarger.getNumOccurrences())
226 elementsAttrElementLimit =
clOptions->elideElementsAttrIfLarger;
227 if (
clOptions->printElementsAttrWithHexIfLarger.getNumOccurrences())
228 elementsAttrHexElementLimit =
229 clOptions->printElementsAttrWithHexIfLarger.getValue();
230 if (
clOptions->elideResourceStringsIfLarger.getNumOccurrences())
231 resourceStringCharLimit =
clOptions->elideResourceStringsIfLarger;
232 printDebugInfoFlag =
clOptions->printDebugInfoOpt;
233 printDebugInfoPrettyFormFlag =
clOptions->printPrettyDebugInfoOpt;
234 printGenericOpFormFlag =
clOptions->printGenericOpFormOpt;
235 assumeVerifiedFlag =
clOptions->assumeVerifiedOpt;
236 printLocalScope =
clOptions->printLocalScopeOpt;
237 skipRegionsFlag =
clOptions->skipRegionsOpt;
238 printValueUsersFlag =
clOptions->printValueUsers;
239 printUniqueSSAIDsFlag =
clOptions->printUniqueSSAIDs;
240 useNameLocAsPrefix =
clOptions->useNameLocAsPrefix;
249 elementsAttrElementLimit = largeElementLimit;
255 elementsAttrHexElementLimit = largeElementLimit;
261 resourceStringCharLimit = largeResourceLimit;
269 printDebugInfoFlag = enable;
270 printDebugInfoPrettyFormFlag = prettyForm;
276 printGenericOpFormFlag = enable;
282 skipRegionsFlag = skip;
288 assumeVerifiedFlag = enable;
296 printLocalScope = enable;
302 printValueUsersFlag = enable;
309 printUniqueSSAIDsFlag = enable;
315 return elementsAttrElementLimit &&
316 *elementsAttrElementLimit < int64_t(attr.getNumElements()) &&
317 !llvm::isa<SplatElementsAttr>(attr);
323 return (elementsAttrHexElementLimit != -1) &&
324 (elementsAttrHexElementLimit < int64_t(attr.getNumElements())) &&
325 !llvm::isa<SplatElementsAttr>(attr);
330 return elementsAttrElementLimit;
335 return elementsAttrHexElementLimit;
340 return resourceStringCharLimit;
345 return printDebugInfoFlag;
350 return printDebugInfoPrettyFormFlag;
355 return printGenericOpFormFlag;
363 return assumeVerifiedFlag;
371 return printValueUsersFlag;
381 return useNameLocAsPrefix;
392 struct NewLineCounter {
393 unsigned curLine = 1;
396 static raw_ostream &
operator<<(raw_ostream &os, NewLineCounter &newLine) {
415 template <
typename Container,
typename UnaryFunctor>
417 llvm::interleaveComma(c,
os, eachFn);
463 function_ref<
void(
unsigned,
bool)> printValueName =
nullptr);
476 bool withKeyword =
false);
480 bool isTopLevel =
false);
516 function_ref<
void(
unsigned,
bool)> printValueName =
nullptr);
540 SymbolAlias(StringRef name, uint32_t suffixIndex,
bool isType,
542 : name(name), suffixIndex(suffixIndex), isType(isType),
543 isDeferrable(isDeferrable) {}
546 void print(raw_ostream &os)
const {
547 os << (isType ?
"!" :
"#") << name;
553 bool isTypeAlias()
const {
return isType; }
556 bool canBeDeferred()
const {
return isDeferrable; }
562 uint32_t suffixIndex : 30;
566 bool isDeferrable : 1;
570 bool isPrinted =
false;
576 class AliasInitializer {
580 llvm::BumpPtrAllocator &aliasAllocator)
581 : interfaces(interfaces), aliasAllocator(aliasAllocator),
582 aliasOS(aliasBuffer) {}
585 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias);
593 std::pair<size_t, size_t>
visit(
Attribute attr,
bool canBeDeferred =
false,
594 bool elideType =
false) {
595 return visitImpl(attr, aliases, canBeDeferred, elideType);
602 std::pair<size_t, size_t>
visit(
Type type,
bool canBeDeferred =
false) {
603 return visitImpl(type, aliases, canBeDeferred);
607 struct InProgressAliasInfo {
608 InProgressAliasInfo()
609 : aliasDepth(0), isType(false), canBeDeferred(false) {}
610 InProgressAliasInfo(StringRef alias)
611 : alias(alias), aliasDepth(1), isType(false), canBeDeferred(false) {}
613 bool operator<(
const InProgressAliasInfo &rhs)
const {
615 if (aliasDepth != rhs.aliasDepth)
616 return aliasDepth < rhs.aliasDepth;
617 if (isType != rhs.isType)
619 return alias < rhs.alias;
624 std::optional<StringRef> alias;
627 unsigned aliasDepth : 30;
631 bool canBeDeferred : 1;
641 template <
typename T,
typename... PrintArgs>
642 std::pair<size_t, size_t>
644 llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
645 bool canBeDeferred, PrintArgs &&...printArgs);
648 void markAliasNonDeferrable(
size_t aliasIndex);
652 template <
typename T>
653 void generateAlias(T symbol, InProgressAliasInfo &alias,
bool canBeDeferred);
657 static void initializeAliases(
658 llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
659 llvm::MapVector<const void *, SymbolAlias> &symbolToAlias);
665 llvm::BumpPtrAllocator &aliasAllocator;
668 llvm::MapVector<const void *, InProgressAliasInfo> aliases;
672 llvm::raw_svector_ostream aliasOS;
680 class DummyAliasOperationPrinter :
private OpAsmPrinter {
682 explicit DummyAliasOperationPrinter(
const OpPrintingFlags &printerFlags,
683 AliasInitializer &initializer)
684 : printerFlags(printerFlags), initializer(initializer) {}
688 void printCustomOrGenericOp(
Operation *op)
override {
690 if (printerFlags.shouldPrintDebugInfo())
691 initializer.visit(op->
getLoc(),
true);
694 if (!printerFlags.shouldPrintGenericOpForm()) {
705 void printGenericOp(
Operation *op,
bool printOpName =
true)
override {
707 if (!printerFlags.shouldSkipRegions()) {
721 printAttribute(attr.getValue());
727 void print(
Block *block,
bool printBlockArgs =
true,
728 bool printBlockTerminator =
true) {
731 if (printBlockArgs) {
736 if (printerFlags.shouldPrintDebugInfo())
738 initializer.visit(arg.getLoc(),
false);
746 auto range = llvm::make_range(
748 std::prev(block->
end(),
749 (!hasTerminator || printBlockTerminator) ? 0 : 1));
751 printCustomOrGenericOp(&op);
756 bool printBlockTerminators,
757 bool printEmptyBlock =
false)
override {
760 if (printerFlags.shouldSkipRegions()) {
765 auto *entryBlock = ®ion.
front();
766 print(entryBlock, printEntryBlockArgs, printBlockTerminators);
767 for (
Block &b : llvm::drop_begin(region, 1))
772 bool omitType)
override {
775 if (printerFlags.shouldPrintDebugInfo())
777 initializer.visit(arg.
getLoc(),
false);
781 void printType(
Type type)
override { initializer.visit(type); }
784 void printAttribute(
Attribute attr)
override { initializer.visit(attr); }
785 void printAttributeWithoutType(
Attribute attr)
override {
786 printAttribute(attr);
788 LogicalResult printAlias(
Attribute attr)
override {
789 initializer.visit(attr);
792 LogicalResult printAlias(
Type type)
override {
793 initializer.visit(type);
798 void printOptionalLocationSpecifier(
Location loc)
override {
808 if (elidedAttrs.empty()) {
810 printAttribute(attr.getValue());
813 llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
816 if (!elidedAttrsSet.contains(attr.getName().strref()))
817 printAttribute(attr.getValue());
819 void printOptionalAttrDictWithKeyword(
822 printOptionalAttrDict(attrs, elidedAttrs);
827 raw_ostream &getStream()
const override {
return os; }
831 void printFloat(
const APFloat &)
override {}
832 void printAffineMapOfSSAIds(AffineMapAttr,
ValueRange)
override {}
835 void increaseIndent()
override {}
836 void decreaseIndent()
override {}
837 void printOperand(
Value)
override {}
838 void printOperand(
Value, raw_ostream &os)
override {
847 void printSymbolName(StringRef)
override {}
848 void printSuccessor(
Block *)
override {}
856 AliasInitializer &initializer;
859 mutable llvm::raw_null_ostream os;
864 explicit DummyAliasDialectAsmPrinter(AliasInitializer &initializer,
867 : initializer(initializer), canBeDeferred(canBeDeferred),
868 childIndices(childIndices) {}
873 template <
typename T,
typename... PrintArgs>
874 size_t printAndVisitNestedAliases(T value, PrintArgs &&...printArgs) {
875 printAndVisitNestedAliasesImpl(value, printArgs...);
876 return maxAliasDepth;
882 void printAndVisitNestedAliasesImpl(
Attribute attr,
bool elideType) {
883 if (!isa<BuiltinDialect>(attr.
getDialect())) {
887 }
else if (llvm::isa<AffineMapAttr, DenseArrayAttr, FloatAttr, IntegerAttr,
888 IntegerSetAttr, UnitAttr>(attr)) {
890 }
else if (
auto distinctAttr = dyn_cast<DistinctAttr>(attr)) {
891 printAttribute(distinctAttr.getReferencedAttr());
892 }
else if (
auto dictAttr = dyn_cast<DictionaryAttr>(attr)) {
894 printAttribute(nestedAttr.getName());
895 printAttribute(nestedAttr.getValue());
897 }
else if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr)) {
898 for (
Attribute nestedAttr : arrayAttr.getValue())
899 printAttribute(nestedAttr);
900 }
else if (
auto typeAttr = dyn_cast<TypeAttr>(attr)) {
902 }
else if (
auto locAttr = dyn_cast<OpaqueLoc>(attr)) {
903 printAttribute(locAttr.getFallbackLocation());
904 }
else if (
auto locAttr = dyn_cast<NameLoc>(attr)) {
905 if (!isa<UnknownLoc>(locAttr.getChildLoc()))
906 printAttribute(locAttr.getChildLoc());
907 }
else if (
auto locAttr = dyn_cast<CallSiteLoc>(attr)) {
908 printAttribute(locAttr.getCallee());
909 printAttribute(locAttr.getCaller());
910 }
else if (
auto locAttr = dyn_cast<FusedLoc>(attr)) {
911 if (
Attribute metadata = locAttr.getMetadata())
912 printAttribute(metadata);
913 for (
Location nestedLoc : locAttr.getLocations())
914 printAttribute(nestedLoc);
919 if (
auto typedAttr = llvm::dyn_cast<TypedAttr>(attr)) {
920 Type attrType = typedAttr.getType();
921 if (!llvm::isa<NoneType>(attrType))
926 void printAndVisitNestedAliasesImpl(
Type type) {
931 if (
auto memrefTy = llvm::dyn_cast<MemRefType>(type)) {
933 MemRefLayoutAttrInterface layout = memrefTy.getLayout();
934 if (!llvm::isa<AffineMapAttr>(layout) || !layout.isIdentity())
935 printAttribute(memrefTy.getLayout());
936 if (memrefTy.getMemorySpace())
937 printAttribute(memrefTy.getMemorySpace());
942 auto visitFn = [&](
auto element) {
944 (void)printAlias(element);
951 recordAliasResult(initializer.visit(type, canBeDeferred));
955 void printAttribute(
Attribute attr)
override {
956 recordAliasResult(initializer.visit(attr, canBeDeferred));
958 void printAttributeWithoutType(
Attribute attr)
override {
960 initializer.visit(attr, canBeDeferred,
true));
962 LogicalResult printAlias(
Attribute attr)
override {
963 printAttribute(attr);
966 LogicalResult printAlias(
Type type)
override {
972 void recordAliasResult(std::pair<size_t, size_t> aliasDepthAndIndex) {
973 childIndices.push_back(aliasDepthAndIndex.second);
974 if (aliasDepthAndIndex.first > maxAliasDepth)
975 maxAliasDepth = aliasDepthAndIndex.first;
980 raw_ostream &getStream()
const override {
return os; }
984 void printFloat(
const APFloat &)
override {}
987 void printSymbolName(StringRef)
override {}
990 LogicalResult pushCyclicPrinting(
const void *opaquePointer)
override {
991 return success(cyclicPrintingStack.insert(opaquePointer));
994 void popCyclicPrinting()
override { cyclicPrintingStack.pop_back(); }
1001 AliasInitializer &initializer;
1010 size_t maxAliasDepth = 0;
1013 mutable llvm::raw_null_ostream os;
1021 StringRef allowedPunctChars =
"$._-",
1022 bool allowTrailingDigit =
true) {
1023 assert(!name.empty() &&
"Shouldn't have an empty name here");
1025 auto validChar = [&](
char ch) {
1026 return llvm::isAlnum(ch) || allowedPunctChars.contains(ch);
1029 auto copyNameToBuffer = [&] {
1030 for (
char ch : name) {
1032 buffer.push_back(ch);
1034 buffer.push_back(
'_');
1036 buffer.append(llvm::utohexstr((
unsigned char)ch));
1043 if (isdigit(name[0]) || (!validChar(name[0]) && name[0] !=
' ')) {
1044 buffer.push_back(
'_');
1051 if (!allowTrailingDigit && isdigit(name.back())) {
1053 buffer.push_back(
'_');
1058 for (
char ch : name) {
1059 if (!validChar(ch)) {
1071 void AliasInitializer::initializeAliases(
1072 llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
1073 llvm::MapVector<const void *, SymbolAlias> &symbolToAlias) {
1075 unprocessedAliases = visitedSymbols.takeVector();
1076 llvm::stable_sort(unprocessedAliases, [](
const auto &lhs,
const auto &rhs) {
1077 return lhs.second < rhs.second;
1080 llvm::StringMap<unsigned> nameCounts;
1081 for (
auto &[symbol, aliasInfo] : unprocessedAliases) {
1082 if (!aliasInfo.alias)
1084 StringRef alias = *aliasInfo.alias;
1085 unsigned nameIndex = nameCounts[alias]++;
1086 symbolToAlias.insert(
1087 {symbol, SymbolAlias(alias, nameIndex, aliasInfo.isType,
1088 aliasInfo.canBeDeferred)});
1092 void AliasInitializer::initialize(
1094 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias) {
1098 DummyAliasOperationPrinter aliasPrinter(printerFlags, *
this);
1099 aliasPrinter.printCustomOrGenericOp(op);
1102 initializeAliases(aliases, attrTypeToAlias);
1105 template <
typename T,
typename... PrintArgs>
1106 std::pair<size_t, size_t> AliasInitializer::visitImpl(
1107 T value, llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
1108 bool canBeDeferred, PrintArgs &&...printArgs) {
1109 auto [it, inserted] =
1110 aliases.insert({value.getAsOpaquePointer(), InProgressAliasInfo()});
1111 size_t aliasIndex = std::distance(aliases.begin(), it);
1115 markAliasNonDeferrable(aliasIndex);
1116 return {
static_cast<size_t>(it->second.aliasDepth), aliasIndex};
1120 generateAlias(value, it->second, canBeDeferred);
1121 it->second.isType = std::is_base_of_v<Type, T>;
1122 it->second.canBeDeferred = canBeDeferred;
1126 DummyAliasDialectAsmPrinter printer(*
this, canBeDeferred, childAliases);
1127 size_t maxAliasDepth =
1128 printer.printAndVisitNestedAliases(value, printArgs...);
1131 it = std::next(aliases.begin(), aliasIndex);
1134 it->second.childIndices = std::move(childAliases);
1136 it->second.aliasDepth = maxAliasDepth + 1;
1139 return {(size_t)it->second.aliasDepth, aliasIndex};
1142 void AliasInitializer::markAliasNonDeferrable(
size_t aliasIndex) {
1143 auto *it = std::next(aliases.begin(), aliasIndex);
1147 if (!it->second.canBeDeferred)
1150 it->second.canBeDeferred =
false;
1153 for (
size_t childIndex : it->second.childIndices)
1154 markAliasNonDeferrable(childIndex);
1157 template <
typename T>
1158 void AliasInitializer::generateAlias(T symbol, InProgressAliasInfo &alias,
1159 bool canBeDeferred) {
1161 for (
const auto &interface : interfaces) {
1163 interface.getAlias(symbol, aliasOS);
1166 nameBuffer = std::move(aliasBuffer);
1167 assert(!nameBuffer.empty() &&
"expected valid alias name");
1172 if (nameBuffer.empty())
1179 name = name.copy(aliasAllocator);
1180 alias = InProgressAliasInfo(name);
1198 LogicalResult getAlias(
Attribute attr, raw_ostream &os)
const;
1202 LogicalResult getAlias(
Type ty, raw_ostream &os)
const;
1206 void printNonDeferredAliases(
AsmPrinter::Impl &p, NewLineCounter &newLine) {
1207 printAliases(p, newLine,
false);
1212 printAliases(p, newLine,
true);
1222 llvm::MapVector<const void *, SymbolAlias> attrTypeToAlias;
1225 llvm::BumpPtrAllocator aliasAllocator;
1229 void AliasState::initialize(
1232 AliasInitializer initializer(interfaces, aliasAllocator);
1233 initializer.initialize(op, printerFlags, attrTypeToAlias);
1236 LogicalResult AliasState::getAlias(
Attribute attr, raw_ostream &os)
const {
1238 if (it == attrTypeToAlias.end())
1240 it->second.print(os);
1244 LogicalResult AliasState::getAlias(
Type ty, raw_ostream &os)
const {
1246 if (it == attrTypeToAlias.end())
1248 if (!it->second.isPrinted)
1251 it->second.print(os);
1255 void AliasState::printAliases(
AsmPrinter::Impl &p, NewLineCounter &newLine,
1257 auto filterFn = [=](
const auto &aliasIt) {
1258 return aliasIt.second.canBeDeferred() == isDeferred;
1260 for (
auto &[opaqueSymbol, alias] :
1261 llvm::make_filter_range(attrTypeToAlias, filterFn)) {
1265 if (alias.isTypeAlias()) {
1268 alias.isPrinted =
true;
1295 class SSANameState {
1298 enum :
unsigned { NameSentinel = ~0U };
1301 SSANameState() =
default;
1306 void printValueID(
Value value,
bool printResultNo, raw_ostream &stream)
const;
1309 void printOperationID(
Operation *op, raw_ostream &stream)
const;
1316 BlockInfo getBlockInfo(
Block *block);
1325 void numberValuesInRegion(
Region ®ion);
1326 void numberValuesInBlock(
Block &block);
1333 void getResultIDAndNumber(
OpResult result,
Value &lookupValue,
1334 std::optional<int> &lookupResultNo)
const;
1337 void setValueName(
Value value, StringRef name);
1341 StringRef uniqueValueName(StringRef name);
1364 llvm::ScopedHashTable<StringRef, char> usedNames;
1365 llvm::BumpPtrAllocator usedNameAllocator;
1368 unsigned nextValueID = 0;
1370 unsigned nextArgumentID = 0;
1372 unsigned nextConflictID = 0;
1381 : printerFlags(printerFlags) {
1382 llvm::SaveAndRestore valueIDSaver(nextValueID);
1383 llvm::SaveAndRestore argumentIDSaver(nextArgumentID);
1384 llvm::SaveAndRestore conflictIDSaver(nextConflictID);
1389 using UsedNamesScopeTy = llvm::ScopedHashTable<StringRef, char>::ScopeTy;
1390 using NamingContext =
1391 std::tuple<Region *, unsigned, unsigned, unsigned, UsedNamesScopeTy *>;
1394 llvm::BumpPtrAllocator allocator;
1397 auto *topLevelNamesScope =
1398 new (allocator.Allocate<UsedNamesScopeTy>()) UsedNamesScopeTy(usedNames);
1402 nameContext.push_back(std::make_tuple(®ion, nextValueID, nextArgumentID,
1403 nextConflictID, topLevelNamesScope));
1405 numberValuesInOp(*op);
1407 while (!nameContext.empty()) {
1409 UsedNamesScopeTy *parentScope;
1413 std::tie(region, std::ignore, std::ignore, std::ignore, parentScope) =
1414 nameContext.pop_back_val();
1416 std::tie(region, nextValueID, nextArgumentID, nextConflictID,
1417 parentScope) = nameContext.pop_back_val();
1421 while (usedNames.getCurScope() != parentScope) {
1422 usedNames.getCurScope()->~UsedNamesScopeTy();
1423 assert((usedNames.getCurScope() !=
nullptr || parentScope ==
nullptr) &&
1424 "top level parentScope must be a nullptr");
1428 auto *curNamesScope =
new (allocator.Allocate<UsedNamesScopeTy>())
1429 UsedNamesScopeTy(usedNames);
1431 numberValuesInRegion(*region);
1435 nameContext.push_back(std::make_tuple(®ion, nextValueID,
1436 nextArgumentID, nextConflictID,
1441 while (usedNames.getCurScope() !=
nullptr)
1442 usedNames.getCurScope()->~UsedNamesScopeTy();
1445 void SSANameState::printValueID(
Value value,
bool printResultNo,
1446 raw_ostream &stream)
const {
1448 stream <<
"<<NULL VALUE>>";
1452 std::optional<int> resultNo;
1453 auto lookupValue = value;
1457 if (
OpResult result = dyn_cast<OpResult>(value))
1458 getResultIDAndNumber(result, lookupValue, resultNo);
1460 auto it = valueIDs.find(lookupValue);
1461 if (it == valueIDs.end()) {
1462 stream <<
"<<UNKNOWN SSA VALUE>>";
1467 if (it->second != NameSentinel) {
1468 stream << it->second;
1470 auto nameIt = valueNames.find(lookupValue);
1471 assert(nameIt != valueNames.end() &&
"Didn't have a name entry?");
1472 stream << nameIt->second;
1475 if (resultNo && printResultNo)
1476 stream <<
'#' << *resultNo;
1479 void SSANameState::printOperationID(
Operation *op, raw_ostream &stream)
const {
1480 auto it = operationIDs.find(op);
1481 if (it == operationIDs.end()) {
1482 stream <<
"<<UNKNOWN OPERATION>>";
1484 stream <<
'%' << it->second;
1489 auto it = opResultGroups.find(op);
1490 return it == opResultGroups.end() ?
ArrayRef<int>() : it->second;
1493 BlockInfo SSANameState::getBlockInfo(
Block *block) {
1494 auto it = blockNames.find(block);
1495 BlockInfo invalidBlock{-1,
"INVALIDBLOCK"};
1496 return it != blockNames.end() ? it->second : invalidBlock;
1499 void SSANameState::shadowRegionArgs(
Region ®ion,
ValueRange namesToUse) {
1500 assert(!region.
empty() &&
"cannot shadow arguments of an empty region");
1502 "incorrect number of names passed in");
1504 "only KnownIsolatedFromAbove ops can shadow names");
1507 for (
unsigned i = 0, e = namesToUse.size(); i != e; ++i) {
1508 auto nameToUse = namesToUse[i];
1509 if (nameToUse ==
nullptr)
1514 llvm::raw_svector_ostream nameStream(nameStr);
1515 printValueID(nameToUse,
true, nameStream);
1518 assert(valueIDs[nameToReplace] == NameSentinel);
1521 auto name = StringRef(nameStream.str()).drop_front();
1524 valueNames[nameToReplace] = name.copy(usedNameAllocator);
1530 StringRef maybeGetValueNameFromLoc(
Value value, StringRef name) {
1532 return maybeNameLoc.getName();
1537 void SSANameState::numberValuesInRegion(
Region ®ion) {
1538 auto setBlockArgNameFn = [&](
Value arg, StringRef name) {
1539 assert(!valueIDs.count(arg) &&
"arg numbered multiple times");
1540 assert(llvm::cast<BlockArgument>(arg).getOwner()->getParent() == ®ion &&
1541 "arg not defined in current region");
1543 name = maybeGetValueNameFromLoc(arg, name);
1544 setValueName(arg, name);
1549 if (
auto asmInterface = dyn_cast<OpAsmOpInterface>(op))
1550 asmInterface.getAsmBlockArgumentNames(region, setBlockArgNameFn);
1555 unsigned nextBlockID = 0;
1556 for (
auto &block : region) {
1559 auto blockInfoIt = blockNames.insert({&block, {-1,
""}});
1560 if (blockInfoIt.second) {
1564 llvm::raw_string_ostream(name) <<
"^bb" << nextBlockID;
1565 blockInfoIt.first->second.name = StringRef(name).copy(usedNameAllocator);
1567 blockInfoIt.first->second.ordering = nextBlockID++;
1569 numberValuesInBlock(block);
1573 void SSANameState::numberValuesInBlock(
Block &block) {
1578 llvm::raw_svector_ostream specialName(specialNameBuffer);
1580 if (valueIDs.count(arg))
1583 specialNameBuffer.resize(strlen(
"arg"));
1584 specialName << nextArgumentID++;
1586 StringRef specialNameStr = specialName.str();
1588 specialNameStr = maybeGetValueNameFromLoc(arg, specialNameStr);
1589 setValueName(arg, specialNameStr);
1593 for (
auto &op : block)
1594 numberValuesInOp(op);
1597 void SSANameState::numberValuesInOp(
Operation &op) {
1600 auto setResultNameFn = [&](
Value result, StringRef name) {
1601 assert(!valueIDs.count(result) &&
"result numbered multiple times");
1602 assert(result.
getDefiningOp() == &op &&
"result not defined by 'op'");
1604 name = maybeGetValueNameFromLoc(result, name);
1605 setValueName(result, name);
1608 if (
int resultNo = llvm::cast<OpResult>(result).getResultNumber())
1609 resultGroups.push_back(resultNo);
1612 auto setBlockNameFn = [&](
Block *block, StringRef name) {
1614 "getAsmBlockArgumentNames callback invoked on a block not directly "
1615 "nested under the current operation");
1616 assert(!blockNames.count(block) &&
"block numbered multiple times");
1619 if (name.data() != tmpBuffer.data()) {
1620 tmpBuffer.append(name);
1621 name = tmpBuffer.str();
1623 name = name.copy(usedNameAllocator);
1624 blockNames[block] = {-1, name};
1628 if (OpAsmOpInterface asmInterface = dyn_cast<OpAsmOpInterface>(&op)) {
1629 asmInterface.getAsmBlockNames(setBlockNameFn);
1630 asmInterface.getAsmResultNames(setResultNameFn);
1635 if (numResults == 0) {
1638 if (operationIDs.try_emplace(&op, nextValueID).second)
1647 setValueName(resultBegin, nameLoc.getName());
1652 if (valueIDs.try_emplace(resultBegin, nextValueID).second)
1656 if (resultGroups.size() != 1) {
1657 llvm::array_pod_sort(resultGroups.begin(), resultGroups.end());
1658 opResultGroups.try_emplace(&op, std::move(resultGroups));
1662 void SSANameState::getResultIDAndNumber(
1664 std::optional<int> &lookupResultNo)
const {
1672 auto resultGroupIt = opResultGroups.find(owner);
1673 if (resultGroupIt == opResultGroups.end()) {
1675 lookupResultNo = resultNo;
1682 const auto *it = llvm::upper_bound(resultGroups, resultNo);
1683 int groupResultNo = 0, groupSize = 0;
1686 if (it == resultGroups.end()) {
1687 groupResultNo = resultGroups.back();
1688 groupSize =
static_cast<int>(owner->
getNumResults()) - resultGroups.back();
1691 groupResultNo = *std::prev(it);
1692 groupSize = *it - groupResultNo;
1697 lookupResultNo = resultNo - groupResultNo;
1698 lookupValue = owner->
getResult(groupResultNo);
1701 void SSANameState::setValueName(
Value value, StringRef name) {
1704 valueIDs[value] = nextValueID++;
1708 valueIDs[value] = NameSentinel;
1709 valueNames[value] = uniqueValueName(name);
1712 StringRef SSANameState::uniqueValueName(StringRef name) {
1717 if (!usedNames.count(name)) {
1718 name = name.copy(usedNameAllocator);
1724 probeName.push_back(
'_');
1726 probeName += llvm::utostr(nextConflictID++);
1727 if (!usedNames.count(probeName)) {
1728 name = probeName.str().copy(usedNameAllocator);
1731 probeName.resize(name.size() + 1);
1735 usedNames.insert(name,
char());
1745 class DistinctState {
1751 uint64_t distinctCounter = 0;
1756 uint64_t DistinctState::getId(
DistinctAttr distinctAttr) {
1757 auto [it, inserted] =
1758 distinctAttrMap.try_emplace(distinctAttr, distinctCounter);
1761 return it->getSecond();
1768 AsmParsedResourceEntry::~AsmParsedResourceEntry() =
default;
1769 AsmResourceBuilder::~AsmResourceBuilder() =
default;
1770 AsmResourceParser::~AsmResourceParser() =
default;
1771 AsmResourcePrinter::~AsmResourcePrinter() =
default;
1775 case AsmResourceEntryKind::Blob:
1777 case AsmResourceEntryKind::Bool:
1779 case AsmResourceEntryKind::String:
1782 llvm_unreachable(
"unknown AsmResourceEntryKind");
1786 std::unique_ptr<ResourceCollection> &collection = keyToResources[key.str()];
1788 collection = std::make_unique<ResourceCollection>(key);
1792 std::vector<std::unique_ptr<AsmResourcePrinter>>
1794 std::vector<std::unique_ptr<AsmResourcePrinter>> printers;
1795 for (
auto &it : keyToResources) {
1796 ResourceCollection *collection = it.second.get();
1798 return collection->buildResources(op, builder);
1800 printers.emplace_back(
1806 LogicalResult FallbackAsmResourceMap::ResourceCollection::parseResource(
1810 FailureOr<AsmResourceBlob> blob = entry.
parseAsBlob();
1813 resources.emplace_back(entry.
getKey(), std::move(*blob));
1820 resources.emplace_back(entry.
getKey(), *value);
1827 resources.emplace_back(entry.
getKey(), std::move(*str));
1834 void FallbackAsmResourceMap::ResourceCollection::buildResources(
1836 for (
const auto &entry : resources) {
1837 if (
const auto *value = std::get_if<AsmResourceBlob>(&entry.value))
1839 else if (
const auto *value = std::get_if<bool>(&entry.value))
1841 else if (
const auto *value = std::get_if<std::string>(&entry.value))
1844 llvm_unreachable(
"unknown AsmResourceEntryKind");
1858 : interfaces(op->
getContext()), nameState(op, printerFlags),
1859 printerFlags(printerFlags), locationMap(locationMap) {}
1862 : interfaces(ctx), printerFlags(printerFlags), locationMap(locationMap) {}
1866 aliasState.initialize(op, printerFlags, interfaces);
1886 return llvm::make_pointee_range(externalResourcePrinters);
1896 (*locationMap)[op] = std::make_pair(line, col);
1902 return dialectResources;
1906 return success(cyclicPrintingStack.insert(opaquePointer));
1922 AliasState aliasState;
1925 SSANameState nameState;
1928 DistinctState distinctState;
1944 template <
typename Range>
1948 [&stream](
const auto &dimSize) {
1949 if (ShapedType::isDynamic(dimSize))
1967 return printerFlags;
1971 auto parentThreadId = llvm::get_threadid();
1973 if (parentThreadId == llvm::get_threadid()) {
1975 diag.print(llvm::dbgs());
1976 llvm::dbgs() <<
"\n";
1982 if (failed(
verify(op))) {
1983 LLVM_DEBUG(llvm::dbgs()
1985 <<
"' failed to verify and will be printed in generic form\n");
1989 return printerFlags;
2008 return impl->getPrinterFlags();
2012 std::unique_ptr<AsmResourcePrinter> printer) {
2013 impl->externalResourcePrinters.emplace_back(std::move(printer));
2018 return impl->getDialectResources();
2026 : os(os), state(state), printerFlags(state.getPrinterFlags()) {}
2034 printLocation(loc, allowAlias);
2040 if (!isTopLevel && succeeded(state.getAliasState().getAlias(loc, os)))
2044 .Case<OpaqueLoc>([&](OpaqueLoc loc) {
2045 printLocationInternal(loc.getFallbackLocation(), pretty);
2047 .Case<UnknownLoc>([&](UnknownLoc loc) {
2055 os << loc.getFilename().getValue();
2057 printEscapedString(loc.getFilename());
2058 if (loc.getEndColumn() == loc.getStartColumn() &&
2059 loc.getStartLine() == loc.getEndLine()) {
2060 os <<
':' << loc.getStartLine() <<
':' << loc.getStartColumn();
2063 if (loc.getStartLine() == loc.getEndLine()) {
2064 os <<
':' << loc.getStartLine() <<
':' << loc.getStartColumn()
2065 <<
" to :" << loc.getEndColumn();
2068 os <<
':' << loc.getStartLine() <<
':' << loc.getStartColumn() <<
" to "
2069 << loc.getEndLine() <<
':' << loc.getEndColumn();
2071 .Case<NameLoc>([&](NameLoc loc) {
2072 printEscapedString(loc.getName());
2075 auto childLoc = loc.getChildLoc();
2076 if (!llvm::isa<UnknownLoc>(childLoc)) {
2078 printLocationInternal(childLoc, pretty);
2082 .Case<CallSiteLoc>([&](CallSiteLoc loc) {
2087 printLocationInternal(callee, pretty);
2089 if (llvm::isa<NameLoc>(callee)) {
2090 if (llvm::isa<FileLineColLoc>(caller)) {
2093 os << newLine <<
" at ";
2096 os << newLine <<
" at ";
2101 printLocationInternal(caller, pretty);
2105 .Case<FusedLoc>([&](
FusedLoc loc) {
2108 if (
Attribute metadata = loc.getMetadata()) {
2116 [&](Location loc) { printLocationInternal(loc, pretty); },
2117 [&]() { os << ", "; });
2120 .Default([&](LocationAttr loc) {
2121 // Assumes that this is a dialect-specific attribute and prints it
2123 printAttribute(loc);
2129 static void printFloatValue(const APFloat &apValue, raw_ostream &os,
2130 bool *printedHex = nullptr) {
2131 // We would like to output the FP constant value in exponential notation,
2132 // but we cannot do this if doing so will lose precision. Check here to
2133 // make sure that we only output it in exponential format if we can parse
2134 // the value back and get the same value.
2135 bool isInf = apValue.isInfinity();
2136 bool isNaN = apValue.isNaN();
2137 if (!isInf && !isNaN) {
2138 SmallString<128> strValue;
2139 apValue.toString(strValue, /*FormatPrecision=*/6, /*FormatMaxPadding=*/0,
2140 /*TruncateZero=*/false);
2142 // Check to make sure that the stringized number is not some string like
2143 // "Inf" or NaN, that atof will accept, but the lexer will not. Check
2144 // that the string matches the "[-+]?[0-9]" regex.
2145 assert(((strValue[0] >= '0
' && strValue[0] <= '9') ||
2146 ((strValue[0] ==
'-' || strValue[0] ==
'+') &&
2147 (strValue[1] >=
'0' && strValue[1] <=
'9'))) &&
2148 "[-+]?[0-9] regex does not match!");
2152 if (APFloat(apValue.getSemantics(), strValue).bitwiseIsEqual(apValue)) {
2160 apValue.toString(strValue);
2163 if (strValue.str().contains(
'.')) {
2174 APInt apInt = apValue.bitcastToAPInt();
2175 apInt.toString(str, 16,
false,
2182 return printLocationInternal(loc,
true,
true);
2186 printLocationInternal(loc,
false,
true);
2194 state.getDialectResources()[resource.
getDialect()].insert(resource);
2202 if (symName.empty() || !isalpha(symName.front()))
2207 symName = symName.drop_while(
2208 [](
char c) {
return llvm::isAlnum(c) || c ==
'.' || c ==
'_'; });
2209 if (symName.empty())
2214 return symName.front() ==
'<' && symName.back() ==
'>';
2219 StringRef dialectName, StringRef symString) {
2220 os << symPrefix << dialectName;
2225 os <<
'.' << symString;
2229 os << '<' << symString << '>
';
2233 static bool isBareIdentifier(StringRef name) {
2234 // By making this unsigned, the value passed in to isalnum will always be
2235 // in the range 0-255. This is important when building with MSVC because
2236 // its implementation will assert. This situation can arise when dealing
2237 // with UTF-8 multibyte characters.
2238 if (name.empty() || (!isalpha(name[0]) && name[0] != '_
'))
2240 return llvm::all_of(name.drop_front(), [](unsigned char c) {
2241 return isalnum(c) || c == '_
' || c == '$
' || c == '.
';
2247 static void printKeywordOrString(StringRef keyword, raw_ostream &os) {
2248 // If it can be represented as a bare identifier, write it directly.
2249 if (isBareIdentifier(keyword)) {
2254 // Otherwise, output the keyword wrapped in quotes with proper escaping.
2256 printEscapedString(keyword, os);
2263 static void printSymbolReference(StringRef symbolRef, raw_ostream &os) {
2264 if (symbolRef.empty()) {
2265 os << "@<<INVALID EMPTY SYMBOL>>
";
2269 printKeywordOrString(symbolRef, os);
2272 // Print out a valid ElementsAttr that is succinct and can represent any
2273 // potential shape/type, for use when eliding a large ElementsAttr.
2275 // We choose to use a dense resource ElementsAttr literal with conspicuous
2276 // content to hopefully alert readers to the fact that this has been elided.
2277 static void printElidedElementsAttr(raw_ostream &os) {
2278 os << R"(dense_resource<__elided__>)
";
2281 LogicalResult AsmPrinter::Impl::printAlias(Attribute attr) {
2282 return state.getAliasState().getAlias(attr, os);
2285 LogicalResult AsmPrinter::Impl::printAlias(Type type) {
2286 return state.getAliasState().getAlias(type, os);
2289 void AsmPrinter::Impl::printAttribute(Attribute attr,
2290 AttrTypeElision typeElision) {
2292 os << "<<NULL ATTRIBUTE>>
";
2296 // Try to print an alias for this attribute.
2297 if (succeeded(printAlias(attr)))
2299 return printAttributeImpl(attr, typeElision);
2302 void AsmPrinter::Impl::printAttributeImpl(Attribute attr,
2303 AttrTypeElision typeElision) {
2304 if (!isa<BuiltinDialect>(attr.getDialect())) {
2305 printDialectAttribute(attr);
2306 } else if (auto opaqueAttr = llvm::dyn_cast<OpaqueAttr>(attr)) {
2307 printDialectSymbol(os, "#
", opaqueAttr.getDialectNamespace(),
2308 opaqueAttr.getAttrData());
2309 } else if (llvm::isa<UnitAttr>(attr)) {
2312 } else if (auto distinctAttr = llvm::dyn_cast<DistinctAttr>(attr)) {
2313 os << "distinct[
" << state.getDistinctState().getId(distinctAttr) << "]<
";
2314 if (!llvm::isa<UnitAttr>(distinctAttr.getReferencedAttr())) {
2315 printAttribute(distinctAttr.getReferencedAttr());
2319 } else if (auto dictAttr = llvm::dyn_cast<DictionaryAttr>(attr)) {
2321 interleaveComma(dictAttr.getValue(),
2322 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2325 } else if (auto intAttr = llvm::dyn_cast<IntegerAttr>(attr)) {
2326 Type intType = intAttr.getType();
2327 if (intType.isSignlessInteger(1)) {
2328 os << (intAttr.getValue().getBoolValue() ? "true" : "false");
2330 // Boolean integer attributes always elides the type.
2334 // Only print attributes as unsigned if they are explicitly unsigned or are
2335 // signless 1-bit values. Indexes, signed values, and multi-bit signless
2336 // values print as signed.
2338 intType.isUnsignedInteger() || intType.isSignlessInteger(1);
2339 intAttr.getValue().print(os, !isUnsigned);
2341 // IntegerAttr elides the type if I64.
2342 if (typeElision == AttrTypeElision::May && intType.isSignlessInteger(64))
2345 } else if (auto floatAttr = llvm::dyn_cast<FloatAttr>(attr)) {
2346 bool printedHex = false;
2347 printFloatValue(floatAttr.getValue(), os, &printedHex);
2349 // FloatAttr elides the type if F64.
2350 if (typeElision == AttrTypeElision::May && floatAttr.getType().isF64() &&
2354 } else if (auto strAttr = llvm::dyn_cast<StringAttr>(attr)) {
2355 printEscapedString(strAttr.getValue());
2357 } else if (auto arrayAttr = llvm::dyn_cast<ArrayAttr>(attr)) {
2359 interleaveComma(arrayAttr.getValue(), [&](Attribute attr) {
2360 printAttribute(attr, AttrTypeElision::May);
2364 } else if (auto affineMapAttr = llvm::dyn_cast<AffineMapAttr>(attr)) {
2365 os << "affine_map<
";
2366 affineMapAttr.getValue().print(os);
2369 // AffineMap always elides the type.
2372 } else if (auto integerSetAttr = llvm::dyn_cast<IntegerSetAttr>(attr)) {
2373 os << "affine_set<
";
2374 integerSetAttr.getValue().print(os);
2377 // IntegerSet always elides the type.
2380 } else if (auto typeAttr = llvm::dyn_cast<TypeAttr>(attr)) {
2381 printType(typeAttr.getValue());
2383 } else if (auto refAttr = llvm::dyn_cast<SymbolRefAttr>(attr)) {
2384 printSymbolReference(refAttr.getRootReference().getValue(), os);
2385 for (FlatSymbolRefAttr nestedRef : refAttr.getNestedReferences()) {
2387 printSymbolReference(nestedRef.getValue(), os);
2390 } else if (auto intOrFpEltAttr =
2391 llvm::dyn_cast<DenseIntOrFPElementsAttr>(attr)) {
2392 if (printerFlags.shouldElideElementsAttr(intOrFpEltAttr)) {
2393 printElidedElementsAttr(os);
2396 printDenseIntOrFPElementsAttr(intOrFpEltAttr, /*allowHex=*/true);
2400 } else if (auto strEltAttr = llvm::dyn_cast<DenseStringElementsAttr>(attr)) {
2401 if (printerFlags.shouldElideElementsAttr(strEltAttr)) {
2402 printElidedElementsAttr(os);
2405 printDenseStringElementsAttr(strEltAttr);
2409 } else if (auto sparseEltAttr = llvm::dyn_cast<SparseElementsAttr>(attr)) {
2410 if (printerFlags.shouldElideElementsAttr(sparseEltAttr.getIndices()) ||
2411 printerFlags.shouldElideElementsAttr(sparseEltAttr.getValues())) {
2412 printElidedElementsAttr(os);
2415 DenseIntElementsAttr indices = sparseEltAttr.getIndices();
2416 if (indices.getNumElements() != 0) {
2417 printDenseIntOrFPElementsAttr(indices, /*allowHex=*/false);
2419 printDenseElementsAttr(sparseEltAttr.getValues(), /*allowHex=*/true);
2423 } else if (auto stridedLayoutAttr = llvm::dyn_cast<StridedLayoutAttr>(attr)) {
2424 stridedLayoutAttr.print(os);
2425 } else if (auto denseArrayAttr = llvm::dyn_cast<DenseArrayAttr>(attr)) {
2427 printType(denseArrayAttr.getElementType());
2428 if (!denseArrayAttr.empty()) {
2430 printDenseArrayAttr(denseArrayAttr);
2434 } else if (auto resourceAttr =
2435 llvm::dyn_cast<DenseResourceElementsAttr>(attr)) {
2436 os << "dense_resource<
";
2437 printResourceHandle(resourceAttr.getRawHandle());
2439 } else if (auto locAttr = llvm::dyn_cast<LocationAttr>(attr)) {
2440 printLocation(locAttr);
2442 llvm::report_fatal_error("Unknown builtin attribute
");
2444 // Don't print the type if we must elide it, or if it is a None type.
2445 if (typeElision != AttrTypeElision::Must) {
2446 if (auto typedAttr = llvm::dyn_cast<TypedAttr>(attr)) {
2447 Type attrType = typedAttr.getType();
2448 if (!llvm::isa<NoneType>(attrType)) {
2450 printType(attrType);
2457 static void printDenseIntElement(const APInt &value, raw_ostream &os,
2459 if (type.isInteger(1))
2460 os << (value.getBoolValue() ? "
true" : "false");
2462 value.print(os, !type.isUnsignedInteger());
2466 printDenseElementsAttrImpl(bool isSplat, ShapedType type, raw_ostream &os,
2467 function_ref<void(unsigned)> printEltFn) {
2468 // Special case for 0-d and splat tensors.
2470 return printEltFn(0);
2472 // Special case for degenerate tensors.
2473 auto numElements = type.getNumElements();
2474 if (numElements == 0)
2477 // We use a mixed-radix counter to iterate through the shape. When we bump a
2478 // non-least-significant digit, we emit a close bracket. When we next emit an
2479 // element we re-open all closed brackets.
2481 // The mixed-radix counter, with radices in 'shape'.
2482 int64_t rank = type.getRank();
2483 SmallVector<unsigned, 4> counter(rank, 0);
2484 // The number of brackets that have been opened and not closed.
2485 unsigned openBrackets = 0;
2487 auto shape = type.getShape();
2488 auto bumpCounter = [&] {
2489 // Bump the least significant digit.
2490 ++counter[rank - 1];
2491 // Iterate backwards bubbling back the increment.
2492 for (unsigned i = rank - 1; i > 0; --i)
2493 if (counter[i] >= shape[i]) {
2494 // Index 'i' is rolled over. Bump (i-1) and close a bracket.
2502 for (unsigned idx = 0, e = numElements; idx != e; ++idx) {
2505 while (openBrackets++ < rank)
2507 openBrackets = rank;
2511 while (openBrackets-- > 0)
2515 void AsmPrinter::Impl::printDenseElementsAttr(DenseElementsAttr attr,
2517 if (auto stringAttr = llvm::dyn_cast<DenseStringElementsAttr>(attr))
2518 return printDenseStringElementsAttr(stringAttr);
2520 printDenseIntOrFPElementsAttr(llvm::cast<DenseIntOrFPElementsAttr>(attr),
2524 void AsmPrinter::Impl::printDenseIntOrFPElementsAttr(
2525 DenseIntOrFPElementsAttr attr, bool allowHex) {
2526 auto type = attr.getType();
2527 auto elementType = type.getElementType();
2529 // Check to see if we should format this attribute as a hex string.
2530 if (allowHex && printerFlags.shouldPrintElementsAttrWithHex(attr)) {
2531 ArrayRef<char> rawData = attr.getRawData();
2532 if (llvm::endianness::native == llvm::endianness::big) {
2533 // Convert endianess in big-endian(BE) machines. `rawData` is BE in BE
2534 // machines. It is converted here to print in LE format.
2535 SmallVector<char, 64> outDataVec(rawData.size());
2536 MutableArrayRef<char> convRawData(outDataVec);
2537 DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
2538 rawData, convRawData, type);
2539 printHexString(convRawData);
2541 printHexString(rawData);
2547 if (ComplexType complexTy = llvm::dyn_cast<ComplexType>(elementType)) {
2548 Type complexElementType = complexTy.getElementType();
2549 // Note: The if and else below had a common lambda function which invoked
2550 // printDenseElementsAttrImpl. This lambda was hitting a bug in gcc 9.1,9.2
2551 // and hence was replaced.
2552 if (llvm::isa<IntegerType>(complexElementType)) {
2553 auto valueIt = attr.value_begin<std::complex<APInt>>();
2554 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2555 auto complexValue = *(valueIt + index);
2557 printDenseIntElement(complexValue.real(), os, complexElementType);
2559 printDenseIntElement(complexValue.imag(), os, complexElementType);
2563 auto valueIt = attr.value_begin<std::complex<APFloat>>();
2564 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2565 auto complexValue = *(valueIt + index);
2567 printFloatValue(complexValue.real(), os);
2569 printFloatValue(complexValue.imag(), os);
2573 } else if (elementType.isIntOrIndex()) {
2574 auto valueIt = attr.value_begin<APInt>();
2575 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2576 printDenseIntElement(*(valueIt + index), os, elementType);
2579 assert(llvm::isa<FloatType>(elementType) && "unexpected element type
");
2580 auto valueIt = attr.value_begin<APFloat>();
2581 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2582 printFloatValue(*(valueIt + index), os);
2587 void AsmPrinter::Impl::printDenseStringElementsAttr(
2588 DenseStringElementsAttr attr) {
2589 ArrayRef<StringRef> data = attr.getRawStringData();
2590 auto printFn = [&](unsigned index) { printEscapedString(data[index]); };
2591 printDenseElementsAttrImpl(attr.isSplat(), attr.getType(), os, printFn);
2594 void AsmPrinter::Impl::printDenseArrayAttr(DenseArrayAttr attr) {
2595 Type type = attr.getElementType();
2596 unsigned bitwidth = type.isInteger(1) ? 8 : type.getIntOrFloatBitWidth();
2597 unsigned byteSize = bitwidth / 8;
2598 ArrayRef<char> data = attr.getRawData();
2600 auto printElementAt = [&](unsigned i) {
2601 APInt value(bitwidth, 0);
2603 llvm::LoadIntFromMemory(
2604 value, reinterpret_cast<const uint8_t *>(data.begin() + byteSize * i),
2607 // Print the data as-is or as a float.
2608 if (type.isIntOrIndex()) {
2609 printDenseIntElement(value, getStream(), type);
2611 APFloat fltVal(llvm::cast<FloatType>(type).getFloatSemantics(), value);
2612 printFloatValue(fltVal, getStream());
2615 llvm::interleaveComma(llvm::seq<unsigned>(0, attr.size()), getStream(),
2619 void AsmPrinter::Impl::printType(Type type) {
2621 os << "<<NULL TYPE>>
";
2625 // Try to print an alias for this type.
2626 if (succeeded(printAlias(type)))
2628 return printTypeImpl(type);
2631 void AsmPrinter::Impl::printTypeImpl(Type type) {
2632 TypeSwitch<Type>(type)
2633 .Case<OpaqueType>([&](OpaqueType opaqueTy) {
2634 printDialectSymbol(os, "!
", opaqueTy.getDialectNamespace(),
2635 opaqueTy.getTypeData());
2637 .Case<IndexType>([&](Type) { os << "index
"; })
2638 .Case<Float4E2M1FNType>([&](Type) { os << "f4E2M1FN
"; })
2639 .Case<Float6E2M3FNType>([&](Type) { os << "f6E2M3FN
"; })
2640 .Case<Float6E3M2FNType>([&](Type) { os << "f6E3M2FN
"; })
2641 .Case<Float8E5M2Type>([&](Type) { os << "f8E5M2
"; })
2642 .Case<Float8E4M3Type>([&](Type) { os << "f8E4M3
"; })
2643 .Case<Float8E4M3FNType>([&](Type) { os << "f8E4M3FN
"; })
2644 .Case<Float8E5M2FNUZType>([&](Type) { os << "f8E5M2FNUZ
"; })
2645 .Case<Float8E4M3FNUZType>([&](Type) { os << "f8E4M3FNUZ
"; })
2646 .Case<Float8E4M3B11FNUZType>([&](Type) { os << "f8E4M3B11FNUZ
"; })
2647 .Case<Float8E3M4Type>([&](Type) { os << "f8E3M4
"; })
2648 .Case<Float8E8M0FNUType>([&](Type) { os << "f8E8M0FNU
"; })
2649 .Case<BFloat16Type>([&](Type) { os << "bf16"; })
2650 .Case<Float16Type>([&](Type) { os << "f16"; })
2651 .Case<FloatTF32Type>([&](Type) { os << "tf32
"; })
2652 .Case<Float32Type>([&](Type) { os << "f32
"; })
2653 .Case<Float64Type>([&](Type) { os << "f64
"; })
2654 .Case<Float80Type>([&](Type) { os << "f80
"; })
2655 .Case<Float128Type>([&](Type) { os << "f128
"; })
2656 .Case<IntegerType>([&](IntegerType integerTy) {
2657 if (integerTy.isSigned())
2659 else if (integerTy.isUnsigned())
2661 os << 'i' << integerTy.getWidth();
2663 .Case<FunctionType>([&](FunctionType funcTy) {
2665 interleaveComma(funcTy.getInputs(), [&](Type ty) { printType(ty); });
2667 ArrayRef<Type> results = funcTy.getResults();
2668 if (results.size() == 1 && !llvm::isa<FunctionType>(results[0])) {
2669 printType(results[0]);
2672 interleaveComma(results, [&](Type ty) { printType(ty); });
2676 .Case<VectorType>([&](VectorType vectorTy) {
2677 auto scalableDims = vectorTy.getScalableDims();
2679 auto vShape = vectorTy.getShape();
2680 unsigned lastDim = vShape.size();
2681 unsigned dimIdx = 0;
2682 for (dimIdx = 0; dimIdx < lastDim; dimIdx++) {
2683 if (!scalableDims.empty() && scalableDims[dimIdx])
2685 os << vShape[dimIdx];
2686 if (!scalableDims.empty() && scalableDims[dimIdx])
2690 printType(vectorTy.getElementType());
2693 .Case<RankedTensorType>([&](RankedTensorType tensorTy) {
2695 printDimensionList(tensorTy.getShape());
2696 if (!tensorTy.getShape().empty())
2698 printType(tensorTy.getElementType());
2699 // Only print the encoding attribute value if set.
2700 if (tensorTy.getEncoding()) {
2702 printAttribute(tensorTy.getEncoding());
2706 .Case<UnrankedTensorType>([&](UnrankedTensorType tensorTy) {
2708 printType(tensorTy.getElementType());
2711 .Case<MemRefType>([&](MemRefType memrefTy) {
2713 printDimensionList(memrefTy.getShape());
2714 if (!memrefTy.getShape().empty())
2716 printType(memrefTy.getElementType());
2717 MemRefLayoutAttrInterface layout = memrefTy.getLayout();
2718 if (!llvm::isa<AffineMapAttr>(layout) || !layout.isIdentity()) {
2720 printAttribute(memrefTy.getLayout(), AttrTypeElision::May);
2722 // Only print the memory space if it is the non-default one.
2723 if (memrefTy.getMemorySpace()) {
2725 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2729 .Case<UnrankedMemRefType>([&](UnrankedMemRefType memrefTy) {
2731 printType(memrefTy.getElementType());
2732 // Only print the memory space if it is the non-default one.
2733 if (memrefTy.getMemorySpace()) {
2735 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2739 .Case<ComplexType>([&](ComplexType complexTy) {
2741 printType(complexTy.getElementType());
2744 .Case<TupleType>([&](TupleType tupleTy) {
2746 interleaveComma(tupleTy.getTypes(),
2747 [&](Type type) { printType(type); });
2750 .Case<NoneType>([&](Type) { os << "none
"; })
2751 .Default([&](Type type) { return printDialectType(type); });
2754 void AsmPrinter::Impl::printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
2755 ArrayRef<StringRef> elidedAttrs,
2757 // If there are no attributes, then there is nothing to be done.
2761 // Functor used to print a filtered attribute list.
2762 auto printFilteredAttributesFn = [&](auto filteredAttrs) {
2763 // Print the 'attributes' keyword if necessary.
2765 os << " attributes
";
2767 // Otherwise, print them all out in braces.
2769 interleaveComma(filteredAttrs,
2770 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2774 // If no attributes are elided, we can directly print with no filtering.
2775 if (elidedAttrs.empty())
2776 return printFilteredAttributesFn(attrs);
2778 // Otherwise, filter out any attributes that shouldn't be included.
2779 llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
2781 auto filteredAttrs = llvm::make_filter_range(attrs, [&](NamedAttribute attr) {
2782 return !elidedAttrsSet.contains(attr.getName().strref());
2784 if (!filteredAttrs.empty())
2785 printFilteredAttributesFn(filteredAttrs);
2787 void AsmPrinter::Impl::printNamedAttribute(NamedAttribute attr) {
2788 // Print the name without quotes if possible.
2789 ::printKeywordOrString(attr.getName().strref(), os);
2791 // Pretty printing elides the attribute value for unit attributes.
2792 if (llvm::isa<UnitAttr>(attr.getValue()))
2796 printAttribute(attr.getValue());
2799 void AsmPrinter::Impl::printDialectAttribute(Attribute attr) {
2800 auto &dialect = attr.getDialect();
2802 // Ask the dialect to serialize the attribute to a string.
2803 std::string attrName;
2805 llvm::raw_string_ostream attrNameStr(attrName);
2806 Impl subPrinter(attrNameStr, state);
2807 DialectAsmPrinter printer(subPrinter);
2808 dialect.printAttribute(attr, printer);
2810 printDialectSymbol(os, "#
", dialect.getNamespace(), attrName);
2813 void AsmPrinter::Impl::printDialectType(Type type) {
2814 auto &dialect = type.getDialect();
2816 // Ask the dialect to serialize the type to a string.
2817 std::string typeName;
2819 llvm::raw_string_ostream typeNameStr(typeName);
2820 Impl subPrinter(typeNameStr, state);
2821 DialectAsmPrinter printer(subPrinter);
2822 dialect.printType(type, printer);
2824 printDialectSymbol(os, "!
", dialect.getNamespace(), typeName);
2827 void AsmPrinter::Impl::printEscapedString(StringRef str) {
2829 llvm::printEscapedString(str, os);
2834 os <<
"\"0x" << llvm::toHex(str) <<
"\"";
2837 printHexString(StringRef(data.data(), data.size()));
2841 return state.pushCyclicPrinting(opaquePointer);
2857 assert(
impl &&
"expected AsmPrinter::getStream to be overriden");
2858 return impl->getStream();
2863 assert(
impl &&
"expected AsmPrinter::printFloat to be overriden");
2868 assert(
impl &&
"expected AsmPrinter::printType to be overriden");
2869 impl->printType(type);
2873 assert(
impl &&
"expected AsmPrinter::printAttribute to be overriden");
2874 impl->printAttribute(attr);
2878 assert(
impl &&
"expected AsmPrinter::printAlias to be overriden");
2879 return impl->printAlias(attr);
2883 assert(
impl &&
"expected AsmPrinter::printAlias to be overriden");
2884 return impl->printAlias(type);
2889 "expected AsmPrinter::printAttributeWithoutType to be overriden");
2894 assert(
impl &&
"expected AsmPrinter::printKeywordOrString to be overriden");
2899 assert(
impl &&
"expected AsmPrinter::printString to be overriden");
2901 printEscapedString(keyword,
getStream());
2906 assert(
impl &&
"expected AsmPrinter::printSymbolName to be overriden");
2911 assert(
impl &&
"expected AsmPrinter::printResourceHandle to be overriden");
2912 impl->printResourceHandle(resource);
2920 return impl->pushCyclicPrinting(opaquePointer);
2931 printAffineExprInternal(expr, BindingStrength::Weak, printValueName);
2937 const char *binopSpelling =
nullptr;
2940 unsigned pos = cast<AffineSymbolExpr>(expr).getPosition();
2942 printValueName(pos,
true);
2948 unsigned pos = cast<AffineDimExpr>(expr).getPosition();
2950 printValueName(pos,
false);
2956 os << cast<AffineConstantExpr>(expr).getValue();
2959 binopSpelling =
" + ";
2962 binopSpelling =
" * ";
2965 binopSpelling =
" floordiv ";
2968 binopSpelling =
" ceildiv ";
2971 binopSpelling =
" mod ";
2975 auto binOp = cast<AffineBinaryOpExpr>(expr);
2981 if (enclosingTightness == BindingStrength::Strong)
2985 auto rhsConst = dyn_cast<AffineConstantExpr>(rhsExpr);
2987 rhsConst.getValue() == -1) {
2989 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
2990 if (enclosingTightness == BindingStrength::Strong)
2995 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
2997 os << binopSpelling;
2998 printAffineExprInternal(rhsExpr, BindingStrength::Strong, printValueName);
3000 if (enclosingTightness == BindingStrength::Strong)
3006 if (enclosingTightness == BindingStrength::Strong)
3011 if (
auto rhs = dyn_cast<AffineBinaryOpExpr>(rhsExpr)) {
3014 if (
auto rrhs = dyn_cast<AffineConstantExpr>(rrhsExpr)) {
3015 if (rrhs.getValue() == -1) {
3016 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
3020 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
3023 printAffineExprInternal(rhs.getLHS(), BindingStrength::Weak,
3027 if (enclosingTightness == BindingStrength::Strong)
3032 if (rrhs.getValue() < -1) {
3033 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
3036 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
3038 os <<
" * " << -rrhs.getValue();
3039 if (enclosingTightness == BindingStrength::Strong)
3048 if (
auto rhsConst = dyn_cast<AffineConstantExpr>(rhsExpr)) {
3049 if (rhsConst.getValue() < 0) {
3050 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
3051 os <<
" - " << -rhsConst.getValue();
3052 if (enclosingTightness == BindingStrength::Strong)
3058 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
3061 printAffineExprInternal(rhsExpr, BindingStrength::Weak, printValueName);
3063 if (enclosingTightness == BindingStrength::Strong)
3068 printAffineExprInternal(expr, BindingStrength::Weak);
3069 isEq ? os <<
" == 0" : os <<
" >= 0";
3075 for (
int i = 0; i < (int)map.
getNumDims() - 1; ++i)
3076 os <<
'd' << i <<
", ";
3085 os <<
's' << i <<
", ";
3094 [&](
AffineExpr expr) { printAffineExpr(expr); });
3101 for (
unsigned i = 1; i < set.
getNumDims(); ++i)
3102 os <<
'd' << i - 1 <<
", ";
3111 os <<
's' << i <<
", ";
3120 for (
int i = 1; i < numConstraints; ++i) {
3124 if (numConstraints >= 1)
3125 printAffineConstraint(set.
getConstraint(numConstraints - 1),
3126 set.
isEq(numConstraints - 1));
3141 explicit OperationPrinter(raw_ostream &os,
AsmStateImpl &state)
3145 void printTopLevelOperation(
Operation *op);
3149 void printFullOpWithIndentAndLoc(
Operation *op);
3155 void printCustomOrGenericOp(
Operation *op)
override;
3157 void printGenericOp(
Operation *op,
bool printOpName)
override;
3160 void printBlockName(
Block *block);
3165 void print(
Block *block,
bool printBlockArgs =
true,
3166 bool printBlockTerminator =
true);
3169 void printValueID(
Value value,
bool printResultNo =
true,
3170 raw_ostream *streamOverride =
nullptr)
const;
3174 raw_ostream *streamOverride =
nullptr)
const;
3182 void printOptionalLocationSpecifier(
Location loc)
override {
3183 printTrailingLocation(loc);
3190 os.indent(currentIndent);
3194 void increaseIndent()
override { currentIndent += indentWidth; }
3197 void decreaseIndent()
override { currentIndent -= indentWidth; }
3206 bool omitType =
false)
override;
3209 void printOperand(
Value value)
override { printValueID(value); }
3210 void printOperand(
Value value, raw_ostream &os)
override {
3211 printValueID(value,
true, &os);
3219 void printOptionalAttrDictWithKeyword(
3227 void printSuccessor(
Block *successor)
override;
3231 void printSuccessorAndUseList(
Block *successor,
3236 bool printBlockTerminators,
bool printEmptyBlock)
override;
3243 state.getSSANameState().shadowRegionArgs(region, namesToUse);
3248 void printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3263 void printValueUsers(
Value value);
3267 void printUserIDs(
Operation *user,
bool prefixComma =
false);
3275 using PrintFn =
function_ref<void(StringRef, ValueFn)>;
3277 ResourceBuilder(PrintFn printFn) : printFn(printFn) {}
3278 ~ResourceBuilder()
override =
default;
3280 void buildBool(StringRef key,
bool data)
final {
3281 printFn(key, [&](raw_ostream &os) { os << (data ?
"true" :
"false"); });
3284 void buildString(StringRef key, StringRef data)
final {
3285 printFn(key, [&](raw_ostream &os) {
3287 llvm::printEscapedString(data, os);
3293 uint32_t dataAlignment)
final {
3294 printFn(key, [&](raw_ostream &os) {
3296 llvm::support::ulittle32_t dataAlignmentLE(dataAlignment);
3298 << llvm::toHex(StringRef(
reinterpret_cast<char *
>(&dataAlignmentLE),
3299 sizeof(dataAlignment)))
3300 << llvm::toHex(StringRef(data.data(), data.size())) <<
"\"";
3309 void printFileMetadataDictionary(
Operation *op);
3315 void printResourceFileMetadata(
function_ref<
void()> checkAddMetadataDict,
3326 const static unsigned indentWidth = 2;
3329 unsigned currentIndent = 0;
3333 void OperationPrinter::printTopLevelOperation(
Operation *op) {
3335 state.getAliasState().printNonDeferredAliases(*
this, newLine);
3338 printFullOpWithIndentAndLoc(op);
3342 state.getAliasState().printDeferredAliases(*
this, newLine);
3345 printFileMetadataDictionary(op);
3348 void OperationPrinter::printFileMetadataDictionary(
Operation *op) {
3349 bool sawMetadataEntry =
false;
3350 auto checkAddMetadataDict = [&] {
3351 if (!std::exchange(sawMetadataEntry,
true))
3352 os << newLine <<
"{-#" << newLine;
3356 printResourceFileMetadata(checkAddMetadataDict, op);
3359 if (sawMetadataEntry)
3360 os << newLine <<
"#-}" << newLine;
3363 void OperationPrinter::printResourceFileMetadata(
3366 bool hadResource =
false;
3367 bool needResourceComma =
false;
3368 bool needEntryComma =
false;
3369 auto processProvider = [&](StringRef dictName, StringRef name,
auto &provider,
3370 auto &&...providerArgs) {
3371 bool hadEntry =
false;
3372 auto printFn = [&](StringRef key, ResourceBuilder::ValueFn valueFn) {
3373 checkAddMetadataDict();
3375 auto printFormatting = [&]() {
3377 if (!std::exchange(hadResource,
true)) {
3378 if (needResourceComma)
3379 os <<
"," << newLine;
3380 os <<
" " << dictName <<
"_resources: {" << newLine;
3383 if (!std::exchange(hadEntry,
true)) {
3385 os <<
"," << newLine;
3386 os <<
" " << name <<
": {" << newLine;
3388 os <<
"," << newLine;
3392 std::optional<uint64_t> charLimit =
3394 if (charLimit.has_value()) {
3395 std::string resourceStr;
3396 llvm::raw_string_ostream ss(resourceStr);
3400 if (resourceStr.size() > charLimit.value())
3404 os <<
" " << key <<
": " << resourceStr;
3407 os <<
" " << key <<
": ";
3411 ResourceBuilder entryBuilder(printFn);
3412 provider.buildResources(op, providerArgs..., entryBuilder);
3414 needEntryComma |= hadEntry;
3416 os << newLine <<
" }";
3422 auto &dialectResources = state.getDialectResources();
3423 StringRef name = interface.getDialect()->getNamespace();
3424 auto it = dialectResources.find(interface.getDialect());
3425 if (it != dialectResources.end())
3426 processProvider(
"dialect", name, interface, it->second);
3428 processProvider(
"dialect", name, interface,
3432 os << newLine <<
" }";
3436 needEntryComma =
false;
3437 needResourceComma = hadResource;
3438 hadResource =
false;
3439 for (
const auto &printer : state.getResourcePrinters())
3440 processProvider(
"external", printer.getName(), printer);
3442 os << newLine <<
" }";
3450 void OperationPrinter::printRegionArgument(
BlockArgument arg,
3458 printOptionalAttrDict(argAttrs);
3460 printTrailingLocation(arg.
getLoc(),
false);
3463 void OperationPrinter::printFullOpWithIndentAndLoc(
Operation *op) {
3465 state.registerOperationLocation(op, newLine.curLine, currentIndent);
3467 os.indent(currentIndent);
3469 printTrailingLocation(op->
getLoc());
3471 printUsersComment(op);
3474 void OperationPrinter::printFullOp(
Operation *op) {
3476 auto printResultGroup = [&](
size_t resultNo,
size_t resultCount) {
3477 printValueID(op->
getResult(resultNo),
false);
3478 if (resultCount > 1)
3479 os <<
':' << resultCount;
3483 ArrayRef<int> resultGroups = state.getSSANameState().getOpResultGroups(op);
3484 if (!resultGroups.empty()) {
3487 interleaveComma(llvm::seq<int>(0, resultGroups.size() - 1), [&](
int i) {
3488 printResultGroup(resultGroups[i],
3489 resultGroups[i + 1] - resultGroups[i]);
3492 printResultGroup(resultGroups.back(), numResults - resultGroups.back());
3495 printResultGroup(0, numResults);
3501 printCustomOrGenericOp(op);
3504 void OperationPrinter::printUsersComment(
Operation *op) {
3508 printOperationID(op);
3509 }
else if (numResults && op->
use_empty()) {
3511 }
else if (numResults && !op->
use_empty()) {
3514 unsigned usedInNResults = 0;
3515 unsigned usedInNOperations = 0;
3518 if (userSet.insert(user).second) {
3519 ++usedInNOperations;
3520 usedInNResults += user->getNumResults();
3525 bool exactlyOneUniqueUse =
3526 usedInNResults <= 1 && usedInNOperations <= 1 && numResults == 1;
3527 os <<
" // " << (exactlyOneUniqueUse ?
"user" :
"users") <<
": ";
3528 bool shouldPrintBrackets = numResults > 1;
3529 auto printOpResult = [&](
OpResult opResult) {
3530 if (shouldPrintBrackets)
3532 printValueUsers(opResult);
3533 if (shouldPrintBrackets)
3537 interleaveComma(op->
getResults(), printOpResult);
3541 void OperationPrinter::printUsersComment(
BlockArgument arg) {
3547 os <<
" is used by ";
3548 printValueUsers(arg);
3553 void OperationPrinter::printValueUsers(
Value value) {
3561 if (userSet.insert(user).second)
3562 printUserIDs(user, index);
3566 void OperationPrinter::printUserIDs(
Operation *user,
bool prefixComma) {
3571 printOperationID(user);
3574 [
this](
Value result) { printValueID(result); });
3578 void OperationPrinter::printCustomOrGenericOp(
Operation *op) {
3584 opInfo->printAssembly(op, *
this, defaultDialectStack.back());
3589 if (
auto opPrinter = dialect->getOperationPrinter(op)) {
3594 if (name.count(
'.') == 1)
3595 name.consume_front((defaultDialectStack.back() +
".").str());
3599 opPrinter(op, *
this);
3606 printGenericOp(op,
true);
3609 void OperationPrinter::printGenericOp(
Operation *op,
bool printOpName) {
3613 interleaveComma(op->
getOperands(), [&](
Value value) { printValueID(value); });
3620 [&](
Block *successor) { printBlockName(successor); });
3632 if (op->getNumRegions() != 0) {
3634 interleaveComma(op->getRegions(), [&](Region ®ion) {
3635 printRegion(region, /*printEntryBlockArgs=*/true,
3636 /*printBlockTerminators=*/true, /*printEmptyBlock=*/true);
3641 printOptionalAttrDict(op->getPropertiesStorage()
3642 ? llvm::to_vector(op->getDiscardableAttrs())
3645 // Print the type signature of the operation.
3647 printFunctionalType(op);
3650 void OperationPrinter::printBlockName(Block *block) {
3651 os << state.getSSANameState().getBlockInfo(block).name;
3654 void OperationPrinter::print(Block *block, bool printBlockArgs,
3655 bool printBlockTerminator) {
3656 // Print the block label and argument list if requested.
3657 if (printBlockArgs) {
3658 os.indent(currentIndent);
3659 printBlockName(block);
3661 // Print the argument list if non-empty.
3662 if (!block->args_empty()) {
3664 interleaveComma(block->getArguments(), [&](BlockArgument arg) {
3667 printType(arg.getType());
3668 // TODO: We should allow location aliases on block arguments.
3669 printTrailingLocation(arg.getLoc(), /*allowAlias*/ false);
3675 // Print out some context information about the predecessors of this block.
3676 if (!block->getParent()) {
3677 os << " // block is not in a region!";
3678 } else if (block->hasNoPredecessors()) {
3679 if (!block->isEntryBlock())
3680 os << " // no predecessors";
3681 } else if (auto *pred = block->getSinglePredecessor()) {
3683 printBlockName(pred);
3685 // We want to print the predecessors in a stable order, not in
3686 // whatever order the use-list is in, so gather and sort them.
3687 SmallVector<BlockInfo, 4> predIDs;
3688 for (auto *pred : block->getPredecessors())
3689 predIDs.push_back(state.getSSANameState().getBlockInfo(pred));
3690 llvm::sort(predIDs, [](BlockInfo lhs, BlockInfo rhs) {
3691 return lhs.ordering < rhs.ordering;
3694 os << " // " << predIDs.size() << " preds: ";
3696 interleaveComma(predIDs, [&](BlockInfo pred) { os << pred.name; });
3701 currentIndent += indentWidth;
3703 if (printerFlags.shouldPrintValueUsers()) {
3704 for (BlockArgument arg : block->getArguments()) {
3705 os.indent(currentIndent);
3706 printUsersComment(arg);
3710 bool hasTerminator =
3711 !block->empty() && block->back().hasTrait<OpTrait::IsTerminator>();
3712 auto range = llvm::make_range(
3714 std::prev(block->end(),
3715 (!hasTerminator || printBlockTerminator) ? 0 : 1));
3716 for (auto &op : range) {
3717 printFullOpWithIndentAndLoc(&op);
3720 currentIndent -= indentWidth;
3723 void OperationPrinter::printValueID(Value value, bool printResultNo,
3724 raw_ostream *streamOverride) const {
3725 state.getSSANameState().printValueID(value, printResultNo,
3726 streamOverride ? *streamOverride : os);
3729 void OperationPrinter::printOperationID(Operation *op,
3730 raw_ostream *streamOverride) const {
3731 state.getSSANameState().printOperationID(op, streamOverride ? *streamOverride
3735 void OperationPrinter::printSuccessor(Block *successor) {
3736 printBlockName(successor);
3739 void OperationPrinter::printSuccessorAndUseList(Block *successor,
3740 ValueRange succOperands) {
3741 printBlockName(successor);
3742 if (succOperands.empty())
3746 interleaveComma(succOperands,
3747 [this](Value operand) { printValueID(operand); });
3749 interleaveComma(succOperands,
3750 [this](Value operand) { printType(operand.getType()); });
3754 void OperationPrinter::printRegion(Region ®ion, bool printEntryBlockArgs,
3755 bool printBlockTerminators,
3756 bool printEmptyBlock) {
3757 if (printerFlags.shouldSkipRegions()) {
3761 os << "{" << newLine;
3762 if (!region.empty()) {
3763 auto restoreDefaultDialect =
3764 llvm::make_scope_exit([&]() { defaultDialectStack.pop_back(); });
3765 if (auto iface = dyn_cast<OpAsmOpInterface>(region.getParentOp()))
3766 defaultDialectStack.push_back(iface.getDefaultDialect());
3768 defaultDialectStack.push_back("");
3770 auto *entryBlock = ®ion.front();
3771 // Force printing the block header if printEmptyBlock is set and the block
3772 // is empty or if printEntryBlockArgs is set and there are arguments to
3774 bool shouldAlwaysPrintBlockHeader =
3775 (printEmptyBlock && entryBlock->empty()) ||
3776 (printEntryBlockArgs && entryBlock->getNumArguments() != 0);
3777 print(entryBlock, shouldAlwaysPrintBlockHeader, printBlockTerminators);
3778 for (auto &b : llvm::drop_begin(region.getBlocks(), 1))
3781 os.indent(currentIndent) << "}";
3784 void OperationPrinter::printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3785 ValueRange operands) {
3787 os << "<<NULL AFFINE MAP>>";
3790 AffineMap map = mapAttr.getValue();
3791 unsigned numDims = map.getNumDims();
3792 auto printValueName = [&](unsigned pos, bool isSymbol) {
3793 unsigned index = isSymbol ? numDims + pos : pos;
3794 assert(index < operands.size());
3797 printValueID(operands[index]);
3802 interleaveComma(map.getResults(), [&](AffineExpr expr) {
3803 printAffineExpr(expr, printValueName);
3807 void OperationPrinter::printAffineExprOfSSAIds(AffineExpr expr,
3808 ValueRange dimOperands,
3809 ValueRange symOperands) {
3810 auto printValueName = [&](unsigned pos, bool isSymbol) {
3812 return printValueID(dimOperands[pos]);
3814 printValueID(symOperands[pos]);
3817 printAffineExpr(expr, printValueName);
3820 //===----------------------------------------------------------------------===//
3821 // print and dump methods
3822 //===----------------------------------------------------------------------===//
3824 void Attribute::print(raw_ostream &os, bool elideType) const {
3826 os << "<<NULL ATTRIBUTE>>";
3830 AsmState state(getContext());
3831 print(os, state, elideType);
3833 void Attribute::print(raw_ostream &os, AsmState &state, bool elideType) const {
3834 using AttrTypeElision = AsmPrinter::Impl::AttrTypeElision;
3835 AsmPrinter::Impl(os, state.getImpl())
3836 .printAttribute(*this, elideType ? AttrTypeElision::Must
3837 : AttrTypeElision::Never);
3840 void Attribute::dump() const {
3841 print(llvm::errs());
3842 llvm::errs() << "\n";
3845 void Attribute::printStripped(raw_ostream &os, AsmState &state) const {
3847 os << "<<NULL ATTRIBUTE>>";
3851 AsmPrinter::Impl subPrinter(os, state.getImpl());
3852 if (succeeded(subPrinter.printAlias(*this)))
3855 auto &dialect = this->getDialect();
3856 uint64_t posPrior = os.tell();
3857 DialectAsmPrinter printer(subPrinter);
3858 dialect.printAttribute(*this, printer);
3859 if (posPrior != os.tell())
3862 // Fallback to printing with prefix if the above failed to write anything
3863 // to the output stream.
3866 void Attribute::printStripped(raw_ostream &os) const {
3868 os << "<<NULL ATTRIBUTE>>";
3872 AsmState state(getContext());
3873 printStripped(os, state);
3876 void Type::print(raw_ostream &os) const {
3878 os << "<<NULL TYPE>>";
3882 AsmState state(getContext());
3885 void Type::print(raw_ostream &os, AsmState &state) const {
3886 AsmPrinter::Impl(os, state.getImpl()).printType(*this);
3889 void Type::dump() const {
3890 print(llvm::errs());
3891 llvm::errs() << "\n";
3894 void AffineMap::dump() const {
3895 print(llvm::errs());
3896 llvm::errs() << "\n";
3899 void IntegerSet::dump() const {
3900 print(llvm::errs());
3901 llvm::errs() << "\n";
3904 void AffineExpr::print(raw_ostream &os) const {
3906 os << "<<NULL AFFINE EXPR>>";
3909 AsmState state(getContext());
3910 AsmPrinter::Impl(os, state.getImpl()).printAffineExpr(*this);
3913 void AffineExpr::dump() const {
3914 print(llvm::errs());
3915 llvm::errs() << "\n";
3918 void AffineMap::print(raw_ostream &os) const {
3920 os << "<<NULL AFFINE MAP>>";
3923 AsmState state(getContext());
3924 AsmPrinter::Impl(os, state.getImpl()).printAffineMap(*this);
3927 void IntegerSet::print(raw_ostream &os) const {
3928 AsmState state(getContext());
3929 AsmPrinter::Impl(os, state.getImpl()).printIntegerSet(*this);
3932 void Value::print(raw_ostream &os) const { print(os, OpPrintingFlags()); }
3933 void Value::print(raw_ostream &os, const OpPrintingFlags &flags) const {
3935 os << "<<NULL VALUE>>";
3939 if (auto *op = getDefiningOp())
3940 return op->print(os, flags);
3941 // TODO: Improve BlockArgument print'ing.
3943 os <<
"<block argument> of type '" << arg.
getType()
3948 os <<
"<<NULL VALUE>>";
3952 if (
auto *op = getDefiningOp())
3953 return op->
print(os, state);
3957 os <<
"<block argument> of type '" << arg.
getType()
3962 print(llvm::errs());
3963 llvm::errs() <<
"\n";
3971 state.getImpl().getSSANameState().printValueID(*
this,
true,
3994 if (
auto result = llvm::dyn_cast<OpResult>(*
this)) {
3997 op = llvm::cast<BlockArgument>(*this).getOwner()->
getParentOp();
3999 os <<
"<<UNKNOWN SSA VALUE>>";
4005 printAsOperand(os, state);
4015 OperationPrinter printer(os, state.getImpl());
4016 if (!getParent() && !state.getPrinterFlags().shouldUseLocalScope()) {
4017 state.getImpl().initializeAliases(
this);
4018 printer.printTopLevelOperation(
this);
4020 printer.printFullOpWithIndentAndLoc(
this);
4026 llvm::errs() <<
"\n";
4031 llvm::errs() <<
"\n";
4037 os <<
"<<UNLINKED BLOCK>>\n";
4048 OperationPrinter(os, state.getImpl()).print(
this);
4057 os <<
"<<UNLINKED BLOCK>>\n";
4061 printAsOperand(os, state);
4064 OperationPrinter printer(os, state.getImpl());
4065 printer.printBlockName(
this);
4080 if (dimensions.empty())
4083 if (dimensions.empty())
4093 <<
"Failed parsing dimension list.";
4104 <<
"Failed parsing dimension list.";
4106 if (shapeArr.empty()) {
4108 <<
"Failed parsing dimension list. Did you mean an empty list? It "
4109 "must be denoted by \"[]\".";
static StringRef sanitizeIdentifier(StringRef name, SmallString< 16 > &buffer, StringRef allowedPunctChars="$._-", bool allowTrailingDigit=true)
Sanitize the given name such that it can be used as a valid identifier.
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 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)
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.
Dialect * getDialect() const
Return the dialect that owns the resource.
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 std::string getResourceKey(const AsmDialectResourceHandle &handle) const
Return a key to use for the given resource.
virtual LogicalResult parseResource(AsmParsedResourceEntry &entry) const
Hook for parsing resource entries.
AliasResult
Holds the result of getAlias hook call.
@ FinalAlias
An alias was provided and it should be used (no other hooks will be checked).
@ NoAlias
The object (type or attribute) is not supported by the hook and an alias was not provided.
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 & 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()
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<T>.
void printType(Type type, AsmPrinter &printer)
Prints an LLVM Dialect type.
LogicalResult parseCommaSeparatedList(llvm::cl::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)
@ 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.