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/OpAsmAttrInterface.cpp.inc"
129 #include "mlir/IR/OpAsmOpInterface.cpp.inc"
130 #include "mlir/IR/OpAsmTypeInterface.cpp.inc"
134 return entry.
emitError() <<
"unknown 'resource' key '" << entry.
getKey()
135 <<
"' for dialect '" << getDialect()->getNamespace()
147 struct AsmPrinterOptions {
148 llvm::cl::opt<int64_t> printElementsAttrWithHexIfLarger{
149 "mlir-print-elementsattrs-with-hex-if-larger",
151 "Print DenseElementsAttrs with a hex string that have "
152 "more elements than the given upper limit (use -1 to disable)")};
154 llvm::cl::opt<unsigned> elideElementsAttrIfLarger{
155 "mlir-elide-elementsattrs-if-larger",
156 llvm::cl::desc(
"Elide ElementsAttrs with \"...\" that have "
157 "more elements than the given upper limit")};
159 llvm::cl::opt<unsigned> elideResourceStringsIfLarger{
160 "mlir-elide-resource-strings-if-larger",
162 "Elide printing value of resources if string is too long in chars.")};
164 llvm::cl::opt<bool> printDebugInfoOpt{
165 "mlir-print-debuginfo", llvm::cl::init(
false),
166 llvm::cl::desc(
"Print debug info in MLIR output")};
168 llvm::cl::opt<bool> printPrettyDebugInfoOpt{
169 "mlir-pretty-debuginfo", llvm::cl::init(
false),
170 llvm::cl::desc(
"Print pretty debug info in MLIR output")};
174 llvm::cl::opt<bool> printGenericOpFormOpt{
175 "mlir-print-op-generic", llvm::cl::init(
false),
176 llvm::cl::desc(
"Print the generic op form"), llvm::cl::Hidden};
178 llvm::cl::opt<bool> assumeVerifiedOpt{
179 "mlir-print-assume-verified", llvm::cl::init(
false),
180 llvm::cl::desc(
"Skip op verification when using custom printers"),
183 llvm::cl::opt<bool> printLocalScopeOpt{
184 "mlir-print-local-scope", llvm::cl::init(
false),
185 llvm::cl::desc(
"Print with local scope and inline information (eliding "
186 "aliases for attributes, types, and locations)")};
188 llvm::cl::opt<bool> skipRegionsOpt{
189 "mlir-print-skip-regions", llvm::cl::init(
false),
190 llvm::cl::desc(
"Skip regions when printing ops.")};
192 llvm::cl::opt<bool> printValueUsers{
193 "mlir-print-value-users", llvm::cl::init(
false),
195 "Print users of operation results and block arguments as a comment")};
197 llvm::cl::opt<bool> printUniqueSSAIDs{
198 "mlir-print-unique-ssa-ids", llvm::cl::init(
false),
199 llvm::cl::desc(
"Print unique SSA ID numbers for values, block arguments "
200 "and naming conflicts across all regions")};
202 llvm::cl::opt<bool> useNameLocAsPrefix{
203 "mlir-use-nameloc-as-prefix", llvm::cl::init(
false),
204 llvm::cl::desc(
"Print SSA IDs using NameLocs as prefixes")};
208 static llvm::ManagedStatic<AsmPrinterOptions>
clOptions;
219 : printDebugInfoFlag(false), printDebugInfoPrettyFormFlag(false),
220 printGenericOpFormFlag(false), skipRegionsFlag(false),
221 assumeVerifiedFlag(false), printLocalScope(false),
222 printValueUsersFlag(false), printUniqueSSAIDsFlag(false),
223 useNameLocAsPrefix(false) {
227 if (
clOptions->elideElementsAttrIfLarger.getNumOccurrences())
228 elementsAttrElementLimit =
clOptions->elideElementsAttrIfLarger;
229 if (
clOptions->printElementsAttrWithHexIfLarger.getNumOccurrences())
230 elementsAttrHexElementLimit =
231 clOptions->printElementsAttrWithHexIfLarger.getValue();
232 if (
clOptions->elideResourceStringsIfLarger.getNumOccurrences())
233 resourceStringCharLimit =
clOptions->elideResourceStringsIfLarger;
234 printDebugInfoFlag =
clOptions->printDebugInfoOpt;
235 printDebugInfoPrettyFormFlag =
clOptions->printPrettyDebugInfoOpt;
236 printGenericOpFormFlag =
clOptions->printGenericOpFormOpt;
237 assumeVerifiedFlag =
clOptions->assumeVerifiedOpt;
238 printLocalScope =
clOptions->printLocalScopeOpt;
239 skipRegionsFlag =
clOptions->skipRegionsOpt;
240 printValueUsersFlag =
clOptions->printValueUsers;
241 printUniqueSSAIDsFlag =
clOptions->printUniqueSSAIDs;
242 useNameLocAsPrefix =
clOptions->useNameLocAsPrefix;
251 elementsAttrElementLimit = largeElementLimit;
257 elementsAttrHexElementLimit = largeElementLimit;
263 resourceStringCharLimit = largeResourceLimit;
271 printDebugInfoFlag = enable;
272 printDebugInfoPrettyFormFlag = prettyForm;
278 printGenericOpFormFlag = enable;
284 skipRegionsFlag = skip;
290 assumeVerifiedFlag = enable;
298 printLocalScope = enable;
304 printValueUsersFlag = enable;
311 printUniqueSSAIDsFlag = enable;
317 return elementsAttrElementLimit &&
318 *elementsAttrElementLimit < int64_t(attr.getNumElements()) &&
319 !llvm::isa<SplatElementsAttr>(attr);
325 return (elementsAttrHexElementLimit != -1) &&
326 (elementsAttrHexElementLimit < int64_t(attr.getNumElements())) &&
327 !llvm::isa<SplatElementsAttr>(attr);
331 useNameLocAsPrefix = enable;
337 return elementsAttrElementLimit;
342 return elementsAttrHexElementLimit;
347 return resourceStringCharLimit;
352 return printDebugInfoFlag;
357 return printDebugInfoPrettyFormFlag;
362 return printGenericOpFormFlag;
370 return assumeVerifiedFlag;
378 return printValueUsersFlag;
388 return useNameLocAsPrefix;
399 struct NewLineCounter {
400 unsigned curLine = 1;
403 static raw_ostream &
operator<<(raw_ostream &os, NewLineCounter &newLine) {
422 template <
typename Container,
typename UnaryFunctor>
424 llvm::interleaveComma(c,
os, eachFn);
470 function_ref<
void(
unsigned,
bool)> printValueName =
nullptr);
483 bool withKeyword =
false);
487 bool isTopLevel =
false);
523 function_ref<
void(
unsigned,
bool)> printValueName =
nullptr);
547 SymbolAlias(StringRef name, uint32_t suffixIndex,
bool isType,
549 : name(name), suffixIndex(suffixIndex), isType(isType),
550 isDeferrable(isDeferrable) {}
553 void print(raw_ostream &os)
const {
554 os << (isType ?
"!" :
"#") << name;
556 if (isdigit(name.back()))
563 bool isTypeAlias()
const {
return isType; }
566 bool canBeDeferred()
const {
return isDeferrable; }
572 uint32_t suffixIndex : 30;
576 bool isDeferrable : 1;
580 bool isPrinted =
false;
586 class AliasInitializer {
590 llvm::BumpPtrAllocator &aliasAllocator)
591 : interfaces(interfaces), aliasAllocator(aliasAllocator),
592 aliasOS(aliasBuffer) {}
595 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias);
603 std::pair<size_t, size_t>
visit(
Attribute attr,
bool canBeDeferred =
false,
604 bool elideType =
false) {
605 return visitImpl(attr, aliases, canBeDeferred, elideType);
612 std::pair<size_t, size_t>
visit(
Type type,
bool canBeDeferred =
false) {
613 return visitImpl(type, aliases, canBeDeferred);
617 struct InProgressAliasInfo {
618 InProgressAliasInfo()
619 : aliasDepth(0), isType(false), canBeDeferred(false) {}
620 InProgressAliasInfo(StringRef alias)
621 : alias(alias), aliasDepth(1), isType(false), canBeDeferred(false) {}
623 bool operator<(
const InProgressAliasInfo &rhs)
const {
625 if (aliasDepth != rhs.aliasDepth)
626 return aliasDepth < rhs.aliasDepth;
627 if (isType != rhs.isType)
629 return alias < rhs.alias;
634 std::optional<StringRef> alias;
637 unsigned aliasDepth : 30;
641 bool canBeDeferred : 1;
651 template <
typename T,
typename... PrintArgs>
652 std::pair<size_t, size_t>
654 llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
655 bool canBeDeferred, PrintArgs &&...printArgs);
658 void markAliasNonDeferrable(
size_t aliasIndex);
662 template <
typename T>
663 void generateAlias(T symbol, InProgressAliasInfo &alias,
bool canBeDeferred);
668 uniqueAliasNameIndex(StringRef alias, llvm::StringMap<unsigned> &nameCounts,
673 static void initializeAliases(
674 llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
675 llvm::MapVector<const void *, SymbolAlias> &symbolToAlias);
681 llvm::BumpPtrAllocator &aliasAllocator;
684 llvm::MapVector<const void *, InProgressAliasInfo> aliases;
688 llvm::raw_svector_ostream aliasOS;
696 class DummyAliasOperationPrinter :
private OpAsmPrinter {
698 explicit DummyAliasOperationPrinter(
const OpPrintingFlags &printerFlags,
699 AliasInitializer &initializer)
700 : printerFlags(printerFlags), initializer(initializer) {}
704 void printCustomOrGenericOp(
Operation *op)
override {
706 if (printerFlags.shouldPrintDebugInfo())
707 initializer.visit(op->
getLoc(),
true);
710 if (!printerFlags.shouldPrintGenericOpForm()) {
721 void printGenericOp(
Operation *op,
bool printOpName =
true)
override {
723 if (!printerFlags.shouldSkipRegions()) {
737 printAttribute(attr.getValue());
743 void print(
Block *block,
bool printBlockArgs =
true,
744 bool printBlockTerminator =
true) {
747 if (printBlockArgs) {
752 if (printerFlags.shouldPrintDebugInfo())
754 initializer.visit(arg.getLoc(),
false);
762 auto range = llvm::make_range(
764 std::prev(block->
end(),
765 (!hasTerminator || printBlockTerminator) ? 0 : 1));
767 printCustomOrGenericOp(&op);
772 bool printBlockTerminators,
773 bool printEmptyBlock =
false)
override {
776 if (printerFlags.shouldSkipRegions()) {
781 auto *entryBlock = ®ion.
front();
782 print(entryBlock, printEntryBlockArgs, printBlockTerminators);
783 for (
Block &b : llvm::drop_begin(region, 1))
788 bool omitType)
override {
791 if (printerFlags.shouldPrintDebugInfo())
793 initializer.visit(arg.
getLoc(),
false);
797 void printType(
Type type)
override { initializer.visit(type); }
800 void printAttribute(
Attribute attr)
override { initializer.visit(attr); }
801 void printAttributeWithoutType(
Attribute attr)
override {
802 printAttribute(attr);
804 LogicalResult printAlias(
Attribute attr)
override {
805 initializer.visit(attr);
808 LogicalResult printAlias(
Type type)
override {
809 initializer.visit(type);
814 void printOptionalLocationSpecifier(
Location loc)
override {
824 if (elidedAttrs.empty()) {
826 printAttribute(attr.getValue());
829 llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
832 if (!elidedAttrsSet.contains(attr.getName().strref()))
833 printAttribute(attr.getValue());
835 void printOptionalAttrDictWithKeyword(
838 printOptionalAttrDict(attrs, elidedAttrs);
843 raw_ostream &getStream()
const override {
return os; }
847 void printFloat(
const APFloat &)
override {}
848 void printAffineMapOfSSAIds(AffineMapAttr,
ValueRange)
override {}
851 void increaseIndent()
override {}
852 void decreaseIndent()
override {}
853 void printOperand(
Value)
override {}
854 void printOperand(
Value, raw_ostream &os)
override {
863 void printSymbolName(StringRef)
override {}
864 void printSuccessor(
Block *)
override {}
872 AliasInitializer &initializer;
875 mutable llvm::raw_null_ostream os;
880 explicit DummyAliasDialectAsmPrinter(AliasInitializer &initializer,
883 : initializer(initializer), canBeDeferred(canBeDeferred),
884 childIndices(childIndices) {}
889 template <
typename T,
typename... PrintArgs>
890 size_t printAndVisitNestedAliases(T value, PrintArgs &&...printArgs) {
891 printAndVisitNestedAliasesImpl(value, printArgs...);
892 return maxAliasDepth;
898 void printAndVisitNestedAliasesImpl(
Attribute attr,
bool elideType) {
899 if (!isa<BuiltinDialect>(attr.
getDialect())) {
903 }
else if (llvm::isa<AffineMapAttr, DenseArrayAttr, FloatAttr, IntegerAttr,
904 IntegerSetAttr, UnitAttr>(attr)) {
906 }
else if (
auto distinctAttr = dyn_cast<DistinctAttr>(attr)) {
907 printAttribute(distinctAttr.getReferencedAttr());
908 }
else if (
auto dictAttr = dyn_cast<DictionaryAttr>(attr)) {
910 printAttribute(nestedAttr.getName());
911 printAttribute(nestedAttr.getValue());
913 }
else if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr)) {
914 for (
Attribute nestedAttr : arrayAttr.getValue())
915 printAttribute(nestedAttr);
916 }
else if (
auto typeAttr = dyn_cast<TypeAttr>(attr)) {
918 }
else if (
auto locAttr = dyn_cast<OpaqueLoc>(attr)) {
919 printAttribute(locAttr.getFallbackLocation());
920 }
else if (
auto locAttr = dyn_cast<NameLoc>(attr)) {
921 if (!isa<UnknownLoc>(locAttr.getChildLoc()))
922 printAttribute(locAttr.getChildLoc());
923 }
else if (
auto locAttr = dyn_cast<CallSiteLoc>(attr)) {
924 printAttribute(locAttr.getCallee());
925 printAttribute(locAttr.getCaller());
926 }
else if (
auto locAttr = dyn_cast<FusedLoc>(attr)) {
927 if (
Attribute metadata = locAttr.getMetadata())
928 printAttribute(metadata);
929 for (
Location nestedLoc : locAttr.getLocations())
930 printAttribute(nestedLoc);
935 if (
auto typedAttr = llvm::dyn_cast<TypedAttr>(attr)) {
936 Type attrType = typedAttr.getType();
937 if (!llvm::isa<NoneType>(attrType))
942 void printAndVisitNestedAliasesImpl(
Type type) {
947 if (
auto memrefTy = llvm::dyn_cast<MemRefType>(type)) {
949 MemRefLayoutAttrInterface layout = memrefTy.getLayout();
950 if (!llvm::isa<AffineMapAttr>(layout) || !layout.isIdentity())
951 printAttribute(memrefTy.getLayout());
952 if (memrefTy.getMemorySpace())
953 printAttribute(memrefTy.getMemorySpace());
958 auto visitFn = [&](
auto element) {
960 (void)printAlias(element);
967 recordAliasResult(initializer.visit(type, canBeDeferred));
971 void printAttribute(
Attribute attr)
override {
972 recordAliasResult(initializer.visit(attr, canBeDeferred));
974 void printAttributeWithoutType(
Attribute attr)
override {
976 initializer.visit(attr, canBeDeferred,
true));
978 LogicalResult printAlias(
Attribute attr)
override {
979 printAttribute(attr);
982 LogicalResult printAlias(
Type type)
override {
988 void recordAliasResult(std::pair<size_t, size_t> aliasDepthAndIndex) {
989 childIndices.push_back(aliasDepthAndIndex.second);
990 if (aliasDepthAndIndex.first > maxAliasDepth)
991 maxAliasDepth = aliasDepthAndIndex.first;
996 raw_ostream &getStream()
const override {
return os; }
1000 void printFloat(
const APFloat &)
override {}
1003 void printSymbolName(StringRef)
override {}
1006 LogicalResult pushCyclicPrinting(
const void *opaquePointer)
override {
1007 return success(cyclicPrintingStack.insert(opaquePointer));
1010 void popCyclicPrinting()
override { cyclicPrintingStack.pop_back(); }
1017 AliasInitializer &initializer;
1026 size_t maxAliasDepth = 0;
1029 mutable llvm::raw_null_ostream os;
1037 StringRef allowedPunctChars =
"$._-") {
1038 assert(!name.empty() &&
"Shouldn't have an empty name here");
1040 auto validChar = [&](
char ch) {
1041 return llvm::isAlnum(ch) || allowedPunctChars.contains(ch);
1044 auto copyNameToBuffer = [&] {
1045 for (
char ch : name) {
1047 buffer.push_back(ch);
1049 buffer.push_back(
'_');
1051 buffer.append(llvm::utohexstr((
unsigned char)ch));
1058 if (isdigit(name[0]) || (!validChar(name[0]) && name[0] !=
' ')) {
1059 buffer.push_back(
'_');
1065 for (
char ch : name) {
1066 if (!validChar(ch)) {
1076 unsigned AliasInitializer::uniqueAliasNameIndex(
1077 StringRef alias, llvm::StringMap<unsigned> &nameCounts,
1079 if (!usedAliases.count(alias)) {
1080 usedAliases.insert(alias);
1087 if (isdigit(alias.back()))
1088 probeAlias.push_back(
'_');
1090 if (nameCounts[probeAlias] == 0)
1091 nameCounts[probeAlias] = 1;
1095 unsigned nameIndex = nameCounts[probeAlias]++;
1096 probeAlias += llvm::utostr(nameIndex);
1097 if (!usedAliases.count(probeAlias)) {
1098 usedAliases.insert(probeAlias);
1102 probeAlias.resize(alias.size() + isdigit(alias.back()) ? 1 : 0);
1108 void AliasInitializer::initializeAliases(
1109 llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
1110 llvm::MapVector<const void *, SymbolAlias> &symbolToAlias) {
1112 unprocessedAliases = visitedSymbols.takeVector();
1113 llvm::stable_sort(unprocessedAliases, llvm::less_second());
1117 llvm::BumpPtrAllocator usedAliasAllocator;
1120 llvm::StringMap<unsigned> nameCounts;
1121 for (
auto &[symbol, aliasInfo] : unprocessedAliases) {
1122 if (!aliasInfo.alias)
1124 StringRef alias = *aliasInfo.alias;
1125 unsigned nameIndex = uniqueAliasNameIndex(alias, nameCounts, usedAliases);
1126 symbolToAlias.insert(
1127 {symbol, SymbolAlias(alias, nameIndex, aliasInfo.isType,
1128 aliasInfo.canBeDeferred)});
1132 void AliasInitializer::initialize(
1134 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias) {
1138 DummyAliasOperationPrinter aliasPrinter(printerFlags, *
this);
1139 aliasPrinter.printCustomOrGenericOp(op);
1142 initializeAliases(aliases, attrTypeToAlias);
1145 template <
typename T,
typename... PrintArgs>
1146 std::pair<size_t, size_t> AliasInitializer::visitImpl(
1147 T value, llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
1148 bool canBeDeferred, PrintArgs &&...printArgs) {
1149 auto [it, inserted] =
1150 aliases.insert({value.getAsOpaquePointer(), InProgressAliasInfo()});
1151 size_t aliasIndex = std::distance(aliases.begin(), it);
1155 markAliasNonDeferrable(aliasIndex);
1156 return {
static_cast<size_t>(it->second.aliasDepth), aliasIndex};
1160 generateAlias(value, it->second, canBeDeferred);
1161 it->second.isType = std::is_base_of_v<Type, T>;
1162 it->second.canBeDeferred = canBeDeferred;
1166 DummyAliasDialectAsmPrinter printer(*
this, canBeDeferred, childAliases);
1167 size_t maxAliasDepth =
1168 printer.printAndVisitNestedAliases(value, printArgs...);
1171 it = std::next(aliases.begin(), aliasIndex);
1174 it->second.childIndices = std::move(childAliases);
1176 it->second.aliasDepth = maxAliasDepth + 1;
1179 return {(size_t)it->second.aliasDepth, aliasIndex};
1182 void AliasInitializer::markAliasNonDeferrable(
size_t aliasIndex) {
1183 auto *it = std::next(aliases.begin(), aliasIndex);
1187 if (!it->second.canBeDeferred)
1190 it->second.canBeDeferred =
false;
1193 for (
size_t childIndex : it->second.childIndices)
1194 markAliasNonDeferrable(childIndex);
1197 template <
typename T>
1198 void AliasInitializer::generateAlias(T symbol, InProgressAliasInfo &alias,
1199 bool canBeDeferred) {
1204 using InterfaceT = std::conditional_t<std::is_base_of_v<Attribute, T>,
1205 OpAsmAttrInterface, OpAsmTypeInterface>;
1206 if (
auto symbolInterface = dyn_cast<InterfaceT>(symbol)) {
1207 symbolInterfaceResult = symbolInterface.getAlias(aliasOS);
1209 nameBuffer = std::move(aliasBuffer);
1210 assert(!nameBuffer.empty() &&
"expected valid alias name");
1214 if (symbolInterfaceResult != OpAsmDialectInterface::AliasResult::FinalAlias) {
1215 for (
const auto &interface : interfaces) {
1217 interface.getAlias(symbol, aliasOS);
1220 nameBuffer = std::move(aliasBuffer);
1221 assert(!nameBuffer.empty() &&
"expected valid alias name");
1222 if (result == OpAsmDialectInterface::AliasResult::FinalAlias)
1227 if (nameBuffer.empty())
1233 name = name.copy(aliasAllocator);
1234 alias = InProgressAliasInfo(name);
1252 LogicalResult getAlias(
Attribute attr, raw_ostream &os)
const;
1256 LogicalResult getAlias(
Type ty, raw_ostream &os)
const;
1260 void printNonDeferredAliases(
AsmPrinter::Impl &p, NewLineCounter &newLine) {
1261 printAliases(p, newLine,
false);
1266 printAliases(p, newLine,
true);
1276 llvm::MapVector<const void *, SymbolAlias> attrTypeToAlias;
1279 llvm::BumpPtrAllocator aliasAllocator;
1283 void AliasState::initialize(
1286 AliasInitializer initializer(interfaces, aliasAllocator);
1287 initializer.initialize(op, printerFlags, attrTypeToAlias);
1290 LogicalResult AliasState::getAlias(
Attribute attr, raw_ostream &os)
const {
1292 if (it == attrTypeToAlias.end())
1294 it->second.print(os);
1298 LogicalResult AliasState::getAlias(
Type ty, raw_ostream &os)
const {
1300 if (it == attrTypeToAlias.end())
1302 if (!it->second.isPrinted)
1305 it->second.print(os);
1309 void AliasState::printAliases(
AsmPrinter::Impl &p, NewLineCounter &newLine,
1311 auto filterFn = [=](
const auto &aliasIt) {
1312 return aliasIt.second.canBeDeferred() == isDeferred;
1314 for (
auto &[opaqueSymbol, alias] :
1315 llvm::make_filter_range(attrTypeToAlias, filterFn)) {
1319 if (alias.isTypeAlias()) {
1322 alias.isPrinted =
true;
1349 class SSANameState {
1352 enum :
unsigned { NameSentinel = ~0U };
1355 SSANameState() =
default;
1360 void printValueID(
Value value,
bool printResultNo, raw_ostream &stream)
const;
1363 void printOperationID(
Operation *op, raw_ostream &stream)
const;
1370 BlockInfo getBlockInfo(
Block *block);
1379 void numberValuesInRegion(
Region ®ion);
1380 void numberValuesInBlock(
Block &block);
1387 void getResultIDAndNumber(
OpResult result,
Value &lookupValue,
1388 std::optional<int> &lookupResultNo)
const;
1391 void setValueName(
Value value, StringRef name);
1395 StringRef uniqueValueName(StringRef name);
1418 llvm::ScopedHashTable<StringRef, char> usedNames;
1419 llvm::BumpPtrAllocator usedNameAllocator;
1422 unsigned nextValueID = 0;
1424 unsigned nextArgumentID = 0;
1426 unsigned nextConflictID = 0;
1435 : printerFlags(printerFlags) {
1436 llvm::SaveAndRestore valueIDSaver(nextValueID);
1437 llvm::SaveAndRestore argumentIDSaver(nextArgumentID);
1438 llvm::SaveAndRestore conflictIDSaver(nextConflictID);
1443 using UsedNamesScopeTy = llvm::ScopedHashTable<StringRef, char>::ScopeTy;
1444 using NamingContext =
1445 std::tuple<Region *, unsigned, unsigned, unsigned, UsedNamesScopeTy *>;
1448 llvm::BumpPtrAllocator allocator;
1451 auto *topLevelNamesScope =
1452 new (allocator.Allocate<UsedNamesScopeTy>()) UsedNamesScopeTy(usedNames);
1456 nameContext.push_back(std::make_tuple(®ion, nextValueID, nextArgumentID,
1457 nextConflictID, topLevelNamesScope));
1459 numberValuesInOp(*op);
1461 while (!nameContext.empty()) {
1463 UsedNamesScopeTy *parentScope;
1467 std::tie(region, std::ignore, std::ignore, std::ignore, parentScope) =
1468 nameContext.pop_back_val();
1470 std::tie(region, nextValueID, nextArgumentID, nextConflictID,
1471 parentScope) = nameContext.pop_back_val();
1475 while (usedNames.getCurScope() != parentScope) {
1476 usedNames.getCurScope()->~UsedNamesScopeTy();
1477 assert((usedNames.getCurScope() !=
nullptr || parentScope ==
nullptr) &&
1478 "top level parentScope must be a nullptr");
1482 auto *curNamesScope =
new (allocator.Allocate<UsedNamesScopeTy>())
1483 UsedNamesScopeTy(usedNames);
1485 numberValuesInRegion(*region);
1489 nameContext.push_back(std::make_tuple(®ion, nextValueID,
1490 nextArgumentID, nextConflictID,
1495 while (usedNames.getCurScope() !=
nullptr)
1496 usedNames.getCurScope()->~UsedNamesScopeTy();
1499 void SSANameState::printValueID(
Value value,
bool printResultNo,
1500 raw_ostream &stream)
const {
1502 stream <<
"<<NULL VALUE>>";
1506 std::optional<int> resultNo;
1507 auto lookupValue = value;
1511 if (
OpResult result = dyn_cast<OpResult>(value))
1512 getResultIDAndNumber(result, lookupValue, resultNo);
1514 auto it = valueIDs.find(lookupValue);
1515 if (it == valueIDs.end()) {
1516 stream <<
"<<UNKNOWN SSA VALUE>>";
1521 if (it->second != NameSentinel) {
1522 stream << it->second;
1524 auto nameIt = valueNames.find(lookupValue);
1525 assert(nameIt != valueNames.end() &&
"Didn't have a name entry?");
1526 stream << nameIt->second;
1529 if (resultNo && printResultNo)
1530 stream <<
'#' << *resultNo;
1533 void SSANameState::printOperationID(
Operation *op, raw_ostream &stream)
const {
1534 auto it = operationIDs.find(op);
1535 if (it == operationIDs.end()) {
1536 stream <<
"<<UNKNOWN OPERATION>>";
1538 stream <<
'%' << it->second;
1543 auto it = opResultGroups.find(op);
1544 return it == opResultGroups.end() ?
ArrayRef<int>() : it->second;
1547 BlockInfo SSANameState::getBlockInfo(
Block *block) {
1548 auto it = blockNames.find(block);
1549 BlockInfo invalidBlock{-1,
"INVALIDBLOCK"};
1550 return it != blockNames.end() ? it->second : invalidBlock;
1553 void SSANameState::shadowRegionArgs(
Region ®ion,
ValueRange namesToUse) {
1554 assert(!region.
empty() &&
"cannot shadow arguments of an empty region");
1556 "incorrect number of names passed in");
1558 "only KnownIsolatedFromAbove ops can shadow names");
1561 for (
unsigned i = 0, e = namesToUse.size(); i != e; ++i) {
1562 auto nameToUse = namesToUse[i];
1563 if (nameToUse ==
nullptr)
1568 llvm::raw_svector_ostream nameStream(nameStr);
1569 printValueID(nameToUse,
true, nameStream);
1572 assert(valueIDs[nameToReplace] == NameSentinel);
1575 auto name = StringRef(nameStream.str()).drop_front();
1578 valueNames[nameToReplace] = name.copy(usedNameAllocator);
1584 StringRef maybeGetValueNameFromLoc(
Value value, StringRef name) {
1586 return maybeNameLoc.getName();
1591 void SSANameState::numberValuesInRegion(
Region ®ion) {
1593 bool opAsmOpInterfaceUsed =
false;
1594 auto setBlockArgNameFn = [&](
Value arg, StringRef name) {
1595 assert(!valueIDs.count(arg) &&
"arg numbered multiple times");
1596 assert(llvm::cast<BlockArgument>(arg).getOwner()->getParent() == ®ion &&
1597 "arg not defined in current region");
1598 opAsmOpInterfaceUsed =
true;
1600 name = maybeGetValueNameFromLoc(arg, name);
1601 setValueName(arg, name);
1606 if (
auto asmInterface = dyn_cast<OpAsmOpInterface>(op))
1607 asmInterface.getAsmBlockArgumentNames(region, setBlockArgNameFn);
1609 if (!opAsmOpInterfaceUsed) {
1611 if (
auto interface = dyn_cast<OpAsmTypeInterface>(arg.
getType())) {
1612 interface.getAsmName(
1613 [&](StringRef name) { setBlockArgNameFn(arg, name); });
1621 unsigned nextBlockID = 0;
1622 for (
auto &block : region) {
1625 auto blockInfoIt = blockNames.insert({&block, {-1,
""}});
1626 if (blockInfoIt.second) {
1630 llvm::raw_string_ostream(name) <<
"^bb" << nextBlockID;
1631 blockInfoIt.first->second.name = StringRef(name).copy(usedNameAllocator);
1633 blockInfoIt.first->second.ordering = nextBlockID++;
1635 numberValuesInBlock(block);
1639 void SSANameState::numberValuesInBlock(
Block &block) {
1644 llvm::raw_svector_ostream specialName(specialNameBuffer);
1646 if (valueIDs.count(arg))
1649 specialNameBuffer.resize(strlen(
"arg"));
1650 specialName << nextArgumentID++;
1652 StringRef specialNameStr = specialName.str();
1654 specialNameStr = maybeGetValueNameFromLoc(arg, specialNameStr);
1655 setValueName(arg, specialNameStr);
1659 for (
auto &op : block)
1660 numberValuesInOp(op);
1663 void SSANameState::numberValuesInOp(
Operation &op) {
1667 bool opAsmOpInterfaceUsed =
false;
1668 auto setResultNameFn = [&](
Value result, StringRef name) {
1669 assert(!valueIDs.count(result) &&
"result numbered multiple times");
1670 assert(result.
getDefiningOp() == &op &&
"result not defined by 'op'");
1671 opAsmOpInterfaceUsed =
true;
1673 name = maybeGetValueNameFromLoc(result, name);
1674 setValueName(result, name);
1677 if (
int resultNo = llvm::cast<OpResult>(result).getResultNumber())
1678 resultGroups.push_back(resultNo);
1681 auto setBlockNameFn = [&](
Block *block, StringRef name) {
1683 "getAsmBlockArgumentNames callback invoked on a block not directly "
1684 "nested under the current operation");
1685 assert(!blockNames.count(block) &&
"block numbered multiple times");
1688 if (name.data() != tmpBuffer.data()) {
1689 tmpBuffer.append(name);
1690 name = tmpBuffer.str();
1692 name = name.copy(usedNameAllocator);
1693 blockNames[block] = {-1, name};
1697 if (OpAsmOpInterface asmInterface = dyn_cast<OpAsmOpInterface>(&op)) {
1698 asmInterface.getAsmBlockNames(setBlockNameFn);
1699 asmInterface.getAsmResultNames(setResultNameFn);
1701 if (!opAsmOpInterfaceUsed) {
1704 bool allHaveOpAsmTypeInterface =
1706 return isa<OpAsmTypeInterface>(type);
1708 if (allHaveOpAsmTypeInterface) {
1710 auto interface = cast<OpAsmTypeInterface>(result.
getType());
1711 interface.getAsmName(
1712 [&](StringRef name) { setResultNameFn(result, name); });
1719 if (numResults == 0) {
1722 if (operationIDs.try_emplace(&op, nextValueID).second)
1731 setValueName(resultBegin, nameLoc.getName());
1736 if (valueIDs.try_emplace(resultBegin, nextValueID).second)
1740 if (resultGroups.size() != 1) {
1741 llvm::array_pod_sort(resultGroups.begin(), resultGroups.end());
1742 opResultGroups.try_emplace(&op, std::move(resultGroups));
1746 void SSANameState::getResultIDAndNumber(
1748 std::optional<int> &lookupResultNo)
const {
1756 auto resultGroupIt = opResultGroups.find(owner);
1757 if (resultGroupIt == opResultGroups.end()) {
1759 lookupResultNo = resultNo;
1766 const auto *it = llvm::upper_bound(resultGroups, resultNo);
1767 int groupResultNo = 0, groupSize = 0;
1770 if (it == resultGroups.end()) {
1771 groupResultNo = resultGroups.back();
1772 groupSize =
static_cast<int>(owner->
getNumResults()) - resultGroups.back();
1775 groupResultNo = *std::prev(it);
1776 groupSize = *it - groupResultNo;
1781 lookupResultNo = resultNo - groupResultNo;
1782 lookupValue = owner->
getResult(groupResultNo);
1785 void SSANameState::setValueName(
Value value, StringRef name) {
1788 valueIDs[value] = nextValueID++;
1792 valueIDs[value] = NameSentinel;
1793 valueNames[value] = uniqueValueName(name);
1796 StringRef SSANameState::uniqueValueName(StringRef name) {
1801 if (!usedNames.count(name)) {
1802 name = name.copy(usedNameAllocator);
1808 probeName.push_back(
'_');
1810 probeName += llvm::utostr(nextConflictID++);
1811 if (!usedNames.count(probeName)) {
1812 name = probeName.str().copy(usedNameAllocator);
1815 probeName.resize(name.size() + 1);
1819 usedNames.insert(name,
char());
1829 class DistinctState {
1835 uint64_t distinctCounter = 0;
1840 uint64_t DistinctState::getId(
DistinctAttr distinctAttr) {
1841 auto [it, inserted] =
1842 distinctAttrMap.try_emplace(distinctAttr, distinctCounter);
1845 return it->getSecond();
1852 AsmParsedResourceEntry::~AsmParsedResourceEntry() =
default;
1853 AsmResourceBuilder::~AsmResourceBuilder() =
default;
1854 AsmResourceParser::~AsmResourceParser() =
default;
1855 AsmResourcePrinter::~AsmResourcePrinter() =
default;
1859 case AsmResourceEntryKind::Blob:
1861 case AsmResourceEntryKind::Bool:
1863 case AsmResourceEntryKind::String:
1866 llvm_unreachable(
"unknown AsmResourceEntryKind");
1870 std::unique_ptr<ResourceCollection> &collection = keyToResources[key.str()];
1872 collection = std::make_unique<ResourceCollection>(key);
1876 std::vector<std::unique_ptr<AsmResourcePrinter>>
1878 std::vector<std::unique_ptr<AsmResourcePrinter>> printers;
1879 for (
auto &it : keyToResources) {
1880 ResourceCollection *collection = it.second.get();
1882 return collection->buildResources(op, builder);
1884 printers.emplace_back(
1890 LogicalResult FallbackAsmResourceMap::ResourceCollection::parseResource(
1894 FailureOr<AsmResourceBlob> blob = entry.
parseAsBlob();
1897 resources.emplace_back(entry.
getKey(), std::move(*blob));
1904 resources.emplace_back(entry.
getKey(), *value);
1911 resources.emplace_back(entry.
getKey(), std::move(*str));
1918 void FallbackAsmResourceMap::ResourceCollection::buildResources(
1920 for (
const auto &entry : resources) {
1921 if (
const auto *value = std::get_if<AsmResourceBlob>(&entry.value))
1923 else if (
const auto *value = std::get_if<bool>(&entry.value))
1925 else if (
const auto *value = std::get_if<std::string>(&entry.value))
1928 llvm_unreachable(
"unknown AsmResourceEntryKind");
1942 : interfaces(op->
getContext()), nameState(op, printerFlags),
1943 printerFlags(printerFlags), locationMap(locationMap) {}
1946 : interfaces(ctx), printerFlags(printerFlags), locationMap(locationMap) {}
1950 aliasState.initialize(op, printerFlags, interfaces);
1970 return llvm::make_pointee_range(externalResourcePrinters);
1980 (*locationMap)[op] = std::make_pair(line, col);
1986 return dialectResources;
1990 return success(cyclicPrintingStack.insert(opaquePointer));
2006 AliasState aliasState;
2009 SSANameState nameState;
2012 DistinctState distinctState;
2028 template <
typename Range>
2032 [&stream](
const auto &dimSize) {
2033 if (ShapedType::isDynamic(dimSize))
2051 return printerFlags;
2055 auto parentThreadId = llvm::get_threadid();
2057 if (parentThreadId == llvm::get_threadid()) {
2059 diag.print(llvm::dbgs());
2060 llvm::dbgs() <<
"\n";
2066 if (failed(
verify(op))) {
2067 LLVM_DEBUG(llvm::dbgs()
2069 <<
"' failed to verify and will be printed in generic form\n");
2073 return printerFlags;
2092 return impl->getPrinterFlags();
2096 std::unique_ptr<AsmResourcePrinter> printer) {
2097 impl->externalResourcePrinters.emplace_back(std::move(printer));
2102 return impl->getDialectResources();
2110 : os(os), state(state), printerFlags(state.getPrinterFlags()) {}
2118 printLocation(loc, allowAlias);
2124 if (!isTopLevel && succeeded(state.getAliasState().getAlias(loc, os)))
2128 .Case<OpaqueLoc>([&](OpaqueLoc loc) {
2129 printLocationInternal(loc.getFallbackLocation(), pretty);
2131 .Case<UnknownLoc>([&](UnknownLoc loc) {
2139 os << loc.getFilename().getValue();
2141 printEscapedString(loc.getFilename());
2142 if (loc.getEndColumn() == loc.getStartColumn() &&
2143 loc.getStartLine() == loc.getEndLine()) {
2144 os <<
':' << loc.getStartLine() <<
':' << loc.getStartColumn();
2147 if (loc.getStartLine() == loc.getEndLine()) {
2148 os <<
':' << loc.getStartLine() <<
':' << loc.getStartColumn()
2149 <<
" to :" << loc.getEndColumn();
2152 os <<
':' << loc.getStartLine() <<
':' << loc.getStartColumn() <<
" to "
2153 << loc.getEndLine() <<
':' << loc.getEndColumn();
2155 .Case<NameLoc>([&](NameLoc loc) {
2156 printEscapedString(loc.getName());
2159 auto childLoc = loc.getChildLoc();
2160 if (!llvm::isa<UnknownLoc>(childLoc)) {
2162 printLocationInternal(childLoc, pretty);
2166 .Case<CallSiteLoc>([&](CallSiteLoc loc) {
2171 printLocationInternal(callee, pretty);
2173 if (llvm::isa<NameLoc>(callee)) {
2174 if (llvm::isa<FileLineColLoc>(caller)) {
2177 os << newLine <<
" at ";
2180 os << newLine <<
" at ";
2185 printLocationInternal(caller, pretty);
2189 .Case<FusedLoc>([&](
FusedLoc loc) {
2192 if (
Attribute metadata = loc.getMetadata()) {
2200 [&](Location loc) { printLocationInternal(loc, pretty); },
2201 [&]() { os << ", "; });
2204 .Default([&](LocationAttr loc) {
2205 // Assumes that this is a dialect-specific attribute and prints it
2207 printAttribute(loc);
2213 static void printFloatValue(const APFloat &apValue, raw_ostream &os,
2214 bool *printedHex = nullptr) {
2215 // We would like to output the FP constant value in exponential notation,
2216 // but we cannot do this if doing so will lose precision. Check here to
2217 // make sure that we only output it in exponential format if we can parse
2218 // the value back and get the same value.
2219 bool isInf = apValue.isInfinity();
2220 bool isNaN = apValue.isNaN();
2221 if (!isInf && !isNaN) {
2222 SmallString<128> strValue;
2223 apValue.toString(strValue, /*FormatPrecision=*/6, /*FormatMaxPadding=*/0,
2224 /*TruncateZero=*/false);
2226 // Check to make sure that the stringized number is not some string like
2227 // "Inf" or NaN, that atof will accept, but the lexer will not. Check
2228 // that the string matches the "[-+]?[0-9]" regex.
2229 assert(((strValue[0] >= '0
' && strValue[0] <= '9') ||
2230 ((strValue[0] ==
'-' || strValue[0] ==
'+') &&
2231 (strValue[1] >=
'0' && strValue[1] <=
'9'))) &&
2232 "[-+]?[0-9] regex does not match!");
2236 if (APFloat(apValue.getSemantics(), strValue).bitwiseIsEqual(apValue)) {
2244 apValue.toString(strValue);
2247 if (strValue.str().contains(
'.')) {
2258 APInt apInt = apValue.bitcastToAPInt();
2259 apInt.toString(str, 16,
false,
2266 return printLocationInternal(loc,
true,
true);
2270 printLocationInternal(loc,
false,
true);
2279 if (symName.empty() || !isalpha(symName.front()))
2284 symName = symName.drop_while(
2285 [](
char c) {
return llvm::isAlnum(c) || c ==
'.' || c ==
'_'; });
2286 if (symName.empty())
2291 return symName.front() ==
'<' && symName.back() ==
'>';
2296 StringRef dialectName, StringRef symString) {
2297 os << symPrefix << dialectName;
2302 os <<
'.' << symString;
2306 os << '<' << symString << '>
';
2310 static bool isBareIdentifier(StringRef name) {
2311 // By making this unsigned, the value passed in to isalnum will always be
2312 // in the range 0-255. This is important when building with MSVC because
2313 // its implementation will assert. This situation can arise when dealing
2314 // with UTF-8 multibyte characters.
2315 if (name.empty() || (!isalpha(name[0]) && name[0] != '_
'))
2317 return llvm::all_of(name.drop_front(), [](unsigned char c) {
2318 return isalnum(c) || c == '_
' || c == '$
' || c == '.
';
2324 static void printKeywordOrString(StringRef keyword, raw_ostream &os) {
2325 // If it can be represented as a bare identifier, write it directly.
2326 if (isBareIdentifier(keyword)) {
2331 // Otherwise, output the keyword wrapped in quotes with proper escaping.
2333 printEscapedString(keyword, os);
2340 static void printSymbolReference(StringRef symbolRef, raw_ostream &os) {
2341 if (symbolRef.empty()) {
2342 os << "@<<INVALID EMPTY SYMBOL>>
";
2346 printKeywordOrString(symbolRef, os);
2349 // Print out a valid ElementsAttr that is succinct and can represent any
2350 // potential shape/type, for use when eliding a large ElementsAttr.
2352 // We choose to use a dense resource ElementsAttr literal with conspicuous
2353 // content to hopefully alert readers to the fact that this has been elided.
2354 static void printElidedElementsAttr(raw_ostream &os) {
2355 os << R"(dense_resource<__elided__>)
";
2358 void AsmPrinter::Impl::printResourceHandle(
2359 const AsmDialectResourceHandle &resource) {
2360 auto *interface = cast<OpAsmDialectInterface>(resource.getDialect());
2361 ::printKeywordOrString(interface->getResourceKey(resource), os);
2362 state.getDialectResources()[resource.getDialect()].insert(resource);
2365 LogicalResult AsmPrinter::Impl::printAlias(Attribute attr) {
2366 return state.getAliasState().getAlias(attr, os);
2369 LogicalResult AsmPrinter::Impl::printAlias(Type type) {
2370 return state.getAliasState().getAlias(type, os);
2373 void AsmPrinter::Impl::printAttribute(Attribute attr,
2374 AttrTypeElision typeElision) {
2376 os << "<<NULL ATTRIBUTE>>
";
2380 // Try to print an alias for this attribute.
2381 if (succeeded(printAlias(attr)))
2383 return printAttributeImpl(attr, typeElision);
2386 void AsmPrinter::Impl::printAttributeImpl(Attribute attr,
2387 AttrTypeElision typeElision) {
2388 if (!isa<BuiltinDialect>(attr.getDialect())) {
2389 printDialectAttribute(attr);
2390 } else if (auto opaqueAttr = llvm::dyn_cast<OpaqueAttr>(attr)) {
2391 printDialectSymbol(os, "#
", opaqueAttr.getDialectNamespace(),
2392 opaqueAttr.getAttrData());
2393 } else if (llvm::isa<UnitAttr>(attr)) {
2396 } else if (auto distinctAttr = llvm::dyn_cast<DistinctAttr>(attr)) {
2397 os << "distinct[
" << state.getDistinctState().getId(distinctAttr) << "]<
";
2398 if (!llvm::isa<UnitAttr>(distinctAttr.getReferencedAttr())) {
2399 printAttribute(distinctAttr.getReferencedAttr());
2403 } else if (auto dictAttr = llvm::dyn_cast<DictionaryAttr>(attr)) {
2405 interleaveComma(dictAttr.getValue(),
2406 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2409 } else if (auto intAttr = llvm::dyn_cast<IntegerAttr>(attr)) {
2410 Type intType = intAttr.getType();
2411 if (intType.isSignlessInteger(1)) {
2412 os << (intAttr.getValue().getBoolValue() ? "true" : "false");
2414 // Boolean integer attributes always elides the type.
2418 // Only print attributes as unsigned if they are explicitly unsigned or are
2419 // signless 1-bit values. Indexes, signed values, and multi-bit signless
2420 // values print as signed.
2422 intType.isUnsignedInteger() || intType.isSignlessInteger(1);
2423 intAttr.getValue().print(os, !isUnsigned);
2425 // IntegerAttr elides the type if I64.
2426 if (typeElision == AttrTypeElision::May && intType.isSignlessInteger(64))
2429 } else if (auto floatAttr = llvm::dyn_cast<FloatAttr>(attr)) {
2430 bool printedHex = false;
2431 printFloatValue(floatAttr.getValue(), os, &printedHex);
2433 // FloatAttr elides the type if F64.
2434 if (typeElision == AttrTypeElision::May && floatAttr.getType().isF64() &&
2438 } else if (auto strAttr = llvm::dyn_cast<StringAttr>(attr)) {
2439 printEscapedString(strAttr.getValue());
2441 } else if (auto arrayAttr = llvm::dyn_cast<ArrayAttr>(attr)) {
2443 interleaveComma(arrayAttr.getValue(), [&](Attribute attr) {
2444 printAttribute(attr, AttrTypeElision::May);
2448 } else if (auto affineMapAttr = llvm::dyn_cast<AffineMapAttr>(attr)) {
2449 os << "affine_map<
";
2450 affineMapAttr.getValue().print(os);
2453 // AffineMap always elides the type.
2456 } else if (auto integerSetAttr = llvm::dyn_cast<IntegerSetAttr>(attr)) {
2457 os << "affine_set<
";
2458 integerSetAttr.getValue().print(os);
2461 // IntegerSet always elides the type.
2464 } else if (auto typeAttr = llvm::dyn_cast<TypeAttr>(attr)) {
2465 printType(typeAttr.getValue());
2467 } else if (auto refAttr = llvm::dyn_cast<SymbolRefAttr>(attr)) {
2468 printSymbolReference(refAttr.getRootReference().getValue(), os);
2469 for (FlatSymbolRefAttr nestedRef : refAttr.getNestedReferences()) {
2471 printSymbolReference(nestedRef.getValue(), os);
2474 } else if (auto intOrFpEltAttr =
2475 llvm::dyn_cast<DenseIntOrFPElementsAttr>(attr)) {
2476 if (printerFlags.shouldElideElementsAttr(intOrFpEltAttr)) {
2477 printElidedElementsAttr(os);
2480 printDenseIntOrFPElementsAttr(intOrFpEltAttr, /*allowHex=*/true);
2484 } else if (auto strEltAttr = llvm::dyn_cast<DenseStringElementsAttr>(attr)) {
2485 if (printerFlags.shouldElideElementsAttr(strEltAttr)) {
2486 printElidedElementsAttr(os);
2489 printDenseStringElementsAttr(strEltAttr);
2493 } else if (auto sparseEltAttr = llvm::dyn_cast<SparseElementsAttr>(attr)) {
2494 if (printerFlags.shouldElideElementsAttr(sparseEltAttr.getIndices()) ||
2495 printerFlags.shouldElideElementsAttr(sparseEltAttr.getValues())) {
2496 printElidedElementsAttr(os);
2499 DenseIntElementsAttr indices = sparseEltAttr.getIndices();
2500 if (indices.getNumElements() != 0) {
2501 printDenseIntOrFPElementsAttr(indices, /*allowHex=*/false);
2503 printDenseElementsAttr(sparseEltAttr.getValues(), /*allowHex=*/true);
2507 } else if (auto stridedLayoutAttr = llvm::dyn_cast<StridedLayoutAttr>(attr)) {
2508 stridedLayoutAttr.print(os);
2509 } else if (auto denseArrayAttr = llvm::dyn_cast<DenseArrayAttr>(attr)) {
2511 printType(denseArrayAttr.getElementType());
2512 if (!denseArrayAttr.empty()) {
2514 printDenseArrayAttr(denseArrayAttr);
2518 } else if (auto resourceAttr =
2519 llvm::dyn_cast<DenseResourceElementsAttr>(attr)) {
2520 os << "dense_resource<
";
2521 printResourceHandle(resourceAttr.getRawHandle());
2523 } else if (auto locAttr = llvm::dyn_cast<LocationAttr>(attr)) {
2524 printLocation(locAttr);
2526 llvm::report_fatal_error("Unknown builtin attribute
");
2528 // Don't print the type if we must elide it, or if it is a None type.
2529 if (typeElision != AttrTypeElision::Must) {
2530 if (auto typedAttr = llvm::dyn_cast<TypedAttr>(attr)) {
2531 Type attrType = typedAttr.getType();
2532 if (!llvm::isa<NoneType>(attrType)) {
2534 printType(attrType);
2541 static void printDenseIntElement(const APInt &value, raw_ostream &os,
2543 if (type.isInteger(1))
2544 os << (value.getBoolValue() ? "
true" : "false");
2546 value.print(os, !type.isUnsignedInteger());
2550 printDenseElementsAttrImpl(bool isSplat, ShapedType type, raw_ostream &os,
2551 function_ref<void(unsigned)> printEltFn) {
2552 // Special case for 0-d and splat tensors.
2554 return printEltFn(0);
2556 // Special case for degenerate tensors.
2557 auto numElements = type.getNumElements();
2558 if (numElements == 0)
2561 // We use a mixed-radix counter to iterate through the shape. When we bump a
2562 // non-least-significant digit, we emit a close bracket. When we next emit an
2563 // element we re-open all closed brackets.
2565 // The mixed-radix counter, with radices in 'shape'.
2566 int64_t rank = type.getRank();
2567 SmallVector<unsigned, 4> counter(rank, 0);
2568 // The number of brackets that have been opened and not closed.
2569 unsigned openBrackets = 0;
2571 auto shape = type.getShape();
2572 auto bumpCounter = [&] {
2573 // Bump the least significant digit.
2574 ++counter[rank - 1];
2575 // Iterate backwards bubbling back the increment.
2576 for (unsigned i = rank - 1; i > 0; --i)
2577 if (counter[i] >= shape[i]) {
2578 // Index 'i' is rolled over. Bump (i-1) and close a bracket.
2586 for (unsigned idx = 0, e = numElements; idx != e; ++idx) {
2589 while (openBrackets++ < rank)
2591 openBrackets = rank;
2595 while (openBrackets-- > 0)
2599 void AsmPrinter::Impl::printDenseElementsAttr(DenseElementsAttr attr,
2601 if (auto stringAttr = llvm::dyn_cast<DenseStringElementsAttr>(attr))
2602 return printDenseStringElementsAttr(stringAttr);
2604 printDenseIntOrFPElementsAttr(llvm::cast<DenseIntOrFPElementsAttr>(attr),
2608 void AsmPrinter::Impl::printDenseIntOrFPElementsAttr(
2609 DenseIntOrFPElementsAttr attr, bool allowHex) {
2610 auto type = attr.getType();
2611 auto elementType = type.getElementType();
2613 // Check to see if we should format this attribute as a hex string.
2614 if (allowHex && printerFlags.shouldPrintElementsAttrWithHex(attr)) {
2615 ArrayRef<char> rawData = attr.getRawData();
2616 if (llvm::endianness::native == llvm::endianness::big) {
2617 // Convert endianess in big-endian(BE) machines. `rawData` is BE in BE
2618 // machines. It is converted here to print in LE format.
2619 SmallVector<char, 64> outDataVec(rawData.size());
2620 MutableArrayRef<char> convRawData(outDataVec);
2621 DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
2622 rawData, convRawData, type);
2623 printHexString(convRawData);
2625 printHexString(rawData);
2631 if (ComplexType complexTy = llvm::dyn_cast<ComplexType>(elementType)) {
2632 Type complexElementType = complexTy.getElementType();
2633 // Note: The if and else below had a common lambda function which invoked
2634 // printDenseElementsAttrImpl. This lambda was hitting a bug in gcc 9.1,9.2
2635 // and hence was replaced.
2636 if (llvm::isa<IntegerType>(complexElementType)) {
2637 auto valueIt = attr.value_begin<std::complex<APInt>>();
2638 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2639 auto complexValue = *(valueIt + index);
2641 printDenseIntElement(complexValue.real(), os, complexElementType);
2643 printDenseIntElement(complexValue.imag(), os, complexElementType);
2647 auto valueIt = attr.value_begin<std::complex<APFloat>>();
2648 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2649 auto complexValue = *(valueIt + index);
2651 printFloatValue(complexValue.real(), os);
2653 printFloatValue(complexValue.imag(), os);
2657 } else if (elementType.isIntOrIndex()) {
2658 auto valueIt = attr.value_begin<APInt>();
2659 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2660 printDenseIntElement(*(valueIt + index), os, elementType);
2663 assert(llvm::isa<FloatType>(elementType) && "unexpected element type
");
2664 auto valueIt = attr.value_begin<APFloat>();
2665 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2666 printFloatValue(*(valueIt + index), os);
2671 void AsmPrinter::Impl::printDenseStringElementsAttr(
2672 DenseStringElementsAttr attr) {
2673 ArrayRef<StringRef> data = attr.getRawStringData();
2674 auto printFn = [&](unsigned index) { printEscapedString(data[index]); };
2675 printDenseElementsAttrImpl(attr.isSplat(), attr.getType(), os, printFn);
2678 void AsmPrinter::Impl::printDenseArrayAttr(DenseArrayAttr attr) {
2679 Type type = attr.getElementType();
2680 unsigned bitwidth = type.isInteger(1) ? 8 : type.getIntOrFloatBitWidth();
2681 unsigned byteSize = bitwidth / 8;
2682 ArrayRef<char> data = attr.getRawData();
2684 auto printElementAt = [&](unsigned i) {
2685 APInt value(bitwidth, 0);
2687 llvm::LoadIntFromMemory(
2688 value, reinterpret_cast<const uint8_t *>(data.begin() + byteSize * i),
2691 // Print the data as-is or as a float.
2692 if (type.isIntOrIndex()) {
2693 printDenseIntElement(value, getStream(), type);
2695 APFloat fltVal(llvm::cast<FloatType>(type).getFloatSemantics(), value);
2696 printFloatValue(fltVal, getStream());
2699 llvm::interleaveComma(llvm::seq<unsigned>(0, attr.size()), getStream(),
2703 void AsmPrinter::Impl::printType(Type type) {
2705 os << "<<NULL TYPE>>
";
2709 // Try to print an alias for this type.
2710 if (succeeded(printAlias(type)))
2712 return printTypeImpl(type);
2715 void AsmPrinter::Impl::printTypeImpl(Type type) {
2716 TypeSwitch<Type>(type)
2717 .Case<OpaqueType>([&](OpaqueType opaqueTy) {
2718 printDialectSymbol(os, "!
", opaqueTy.getDialectNamespace(),
2719 opaqueTy.getTypeData());
2721 .Case<IndexType>([&](Type) { os << "index
"; })
2722 .Case<Float4E2M1FNType>([&](Type) { os << "f4E2M1FN
"; })
2723 .Case<Float6E2M3FNType>([&](Type) { os << "f6E2M3FN
"; })
2724 .Case<Float6E3M2FNType>([&](Type) { os << "f6E3M2FN
"; })
2725 .Case<Float8E5M2Type>([&](Type) { os << "f8E5M2
"; })
2726 .Case<Float8E4M3Type>([&](Type) { os << "f8E4M3
"; })
2727 .Case<Float8E4M3FNType>([&](Type) { os << "f8E4M3FN
"; })
2728 .Case<Float8E5M2FNUZType>([&](Type) { os << "f8E5M2FNUZ
"; })
2729 .Case<Float8E4M3FNUZType>([&](Type) { os << "f8E4M3FNUZ
"; })
2730 .Case<Float8E4M3B11FNUZType>([&](Type) { os << "f8E4M3B11FNUZ
"; })
2731 .Case<Float8E3M4Type>([&](Type) { os << "f8E3M4
"; })
2732 .Case<Float8E8M0FNUType>([&](Type) { os << "f8E8M0FNU
"; })
2733 .Case<BFloat16Type>([&](Type) { os << "bf16"; })
2734 .Case<Float16Type>([&](Type) { os << "f16"; })
2735 .Case<FloatTF32Type>([&](Type) { os << "tf32
"; })
2736 .Case<Float32Type>([&](Type) { os << "f32
"; })
2737 .Case<Float64Type>([&](Type) { os << "f64
"; })
2738 .Case<Float80Type>([&](Type) { os << "f80
"; })
2739 .Case<Float128Type>([&](Type) { os << "f128
"; })
2740 .Case<IntegerType>([&](IntegerType integerTy) {
2741 if (integerTy.isSigned())
2743 else if (integerTy.isUnsigned())
2745 os << 'i' << integerTy.getWidth();
2747 .Case<FunctionType>([&](FunctionType funcTy) {
2749 interleaveComma(funcTy.getInputs(), [&](Type ty) { printType(ty); });
2751 ArrayRef<Type> results = funcTy.getResults();
2752 if (results.size() == 1 && !llvm::isa<FunctionType>(results[0])) {
2753 printType(results[0]);
2756 interleaveComma(results, [&](Type ty) { printType(ty); });
2760 .Case<VectorType>([&](VectorType vectorTy) {
2761 auto scalableDims = vectorTy.getScalableDims();
2763 auto vShape = vectorTy.getShape();
2764 unsigned lastDim = vShape.size();
2765 unsigned dimIdx = 0;
2766 for (dimIdx = 0; dimIdx < lastDim; dimIdx++) {
2767 if (!scalableDims.empty() && scalableDims[dimIdx])
2769 os << vShape[dimIdx];
2770 if (!scalableDims.empty() && scalableDims[dimIdx])
2774 printType(vectorTy.getElementType());
2777 .Case<RankedTensorType>([&](RankedTensorType tensorTy) {
2779 printDimensionList(tensorTy.getShape());
2780 if (!tensorTy.getShape().empty())
2782 printType(tensorTy.getElementType());
2783 // Only print the encoding attribute value if set.
2784 if (tensorTy.getEncoding()) {
2786 printAttribute(tensorTy.getEncoding());
2790 .Case<UnrankedTensorType>([&](UnrankedTensorType tensorTy) {
2792 printType(tensorTy.getElementType());
2795 .Case<MemRefType>([&](MemRefType memrefTy) {
2797 printDimensionList(memrefTy.getShape());
2798 if (!memrefTy.getShape().empty())
2800 printType(memrefTy.getElementType());
2801 MemRefLayoutAttrInterface layout = memrefTy.getLayout();
2802 if (!llvm::isa<AffineMapAttr>(layout) || !layout.isIdentity()) {
2804 printAttribute(memrefTy.getLayout(), AttrTypeElision::May);
2806 // Only print the memory space if it is the non-default one.
2807 if (memrefTy.getMemorySpace()) {
2809 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2813 .Case<UnrankedMemRefType>([&](UnrankedMemRefType memrefTy) {
2815 printType(memrefTy.getElementType());
2816 // Only print the memory space if it is the non-default one.
2817 if (memrefTy.getMemorySpace()) {
2819 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2823 .Case<ComplexType>([&](ComplexType complexTy) {
2825 printType(complexTy.getElementType());
2828 .Case<TupleType>([&](TupleType tupleTy) {
2830 interleaveComma(tupleTy.getTypes(),
2831 [&](Type type) { printType(type); });
2834 .Case<NoneType>([&](Type) { os << "none
"; })
2835 .Default([&](Type type) { return printDialectType(type); });
2838 void AsmPrinter::Impl::printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
2839 ArrayRef<StringRef> elidedAttrs,
2841 // If there are no attributes, then there is nothing to be done.
2845 // Functor used to print a filtered attribute list.
2846 auto printFilteredAttributesFn = [&](auto filteredAttrs) {
2847 // Print the 'attributes' keyword if necessary.
2849 os << " attributes
";
2851 // Otherwise, print them all out in braces.
2853 interleaveComma(filteredAttrs,
2854 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2858 // If no attributes are elided, we can directly print with no filtering.
2859 if (elidedAttrs.empty())
2860 return printFilteredAttributesFn(attrs);
2862 // Otherwise, filter out any attributes that shouldn't be included.
2863 llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
2865 auto filteredAttrs = llvm::make_filter_range(attrs, [&](NamedAttribute attr) {
2866 return !elidedAttrsSet.contains(attr.getName().strref());
2868 if (!filteredAttrs.empty())
2869 printFilteredAttributesFn(filteredAttrs);
2871 void AsmPrinter::Impl::printNamedAttribute(NamedAttribute attr) {
2872 // Print the name without quotes if possible.
2873 ::printKeywordOrString(attr.getName().strref(), os);
2875 // Pretty printing elides the attribute value for unit attributes.
2876 if (llvm::isa<UnitAttr>(attr.getValue()))
2880 printAttribute(attr.getValue());
2883 void AsmPrinter::Impl::printDialectAttribute(Attribute attr) {
2884 auto &dialect = attr.getDialect();
2886 // Ask the dialect to serialize the attribute to a string.
2887 std::string attrName;
2889 llvm::raw_string_ostream attrNameStr(attrName);
2890 Impl subPrinter(attrNameStr, state);
2891 DialectAsmPrinter printer(subPrinter);
2892 dialect.printAttribute(attr, printer);
2894 printDialectSymbol(os, "#
", dialect.getNamespace(), attrName);
2897 void AsmPrinter::Impl::printDialectType(Type type) {
2898 auto &dialect = type.getDialect();
2900 // Ask the dialect to serialize the type to a string.
2901 std::string typeName;
2903 llvm::raw_string_ostream typeNameStr(typeName);
2904 Impl subPrinter(typeNameStr, state);
2905 DialectAsmPrinter printer(subPrinter);
2906 dialect.printType(type, printer);
2908 printDialectSymbol(os, "!
", dialect.getNamespace(), typeName);
2911 void AsmPrinter::Impl::printEscapedString(StringRef str) {
2913 llvm::printEscapedString(str, os);
2918 os <<
"\"0x" << llvm::toHex(str) <<
"\"";
2921 printHexString(StringRef(data.data(), data.size()));
2925 return state.pushCyclicPrinting(opaquePointer);
2941 assert(
impl &&
"expected AsmPrinter::getStream to be overriden");
2942 return impl->getStream();
2947 assert(
impl &&
"expected AsmPrinter::printFloat to be overriden");
2952 assert(
impl &&
"expected AsmPrinter::printType to be overriden");
2953 impl->printType(type);
2957 assert(
impl &&
"expected AsmPrinter::printAttribute to be overriden");
2958 impl->printAttribute(attr);
2962 assert(
impl &&
"expected AsmPrinter::printAlias to be overriden");
2963 return impl->printAlias(attr);
2967 assert(
impl &&
"expected AsmPrinter::printAlias to be overriden");
2968 return impl->printAlias(type);
2973 "expected AsmPrinter::printAttributeWithoutType to be overriden");
2978 assert(
impl &&
"expected AsmPrinter::printKeywordOrString to be overriden");
2983 assert(
impl &&
"expected AsmPrinter::printString to be overriden");
2985 printEscapedString(keyword,
getStream());
2990 assert(
impl &&
"expected AsmPrinter::printSymbolName to be overriden");
2995 assert(
impl &&
"expected AsmPrinter::printResourceHandle to be overriden");
2996 impl->printResourceHandle(resource);
3004 return impl->pushCyclicPrinting(opaquePointer);
3015 printAffineExprInternal(expr, BindingStrength::Weak, printValueName);
3021 const char *binopSpelling =
nullptr;
3024 unsigned pos = cast<AffineSymbolExpr>(expr).getPosition();
3026 printValueName(pos,
true);
3032 unsigned pos = cast<AffineDimExpr>(expr).getPosition();
3034 printValueName(pos,
false);
3040 os << cast<AffineConstantExpr>(expr).getValue();
3043 binopSpelling =
" + ";
3046 binopSpelling =
" * ";
3049 binopSpelling =
" floordiv ";
3052 binopSpelling =
" ceildiv ";
3055 binopSpelling =
" mod ";
3059 auto binOp = cast<AffineBinaryOpExpr>(expr);
3065 if (enclosingTightness == BindingStrength::Strong)
3069 auto rhsConst = dyn_cast<AffineConstantExpr>(rhsExpr);
3071 rhsConst.getValue() == -1) {
3073 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
3074 if (enclosingTightness == BindingStrength::Strong)
3079 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
3081 os << binopSpelling;
3082 printAffineExprInternal(rhsExpr, BindingStrength::Strong, printValueName);
3084 if (enclosingTightness == BindingStrength::Strong)
3090 if (enclosingTightness == BindingStrength::Strong)
3095 if (
auto rhs = dyn_cast<AffineBinaryOpExpr>(rhsExpr)) {
3098 if (
auto rrhs = dyn_cast<AffineConstantExpr>(rrhsExpr)) {
3099 if (rrhs.getValue() == -1) {
3100 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
3104 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
3107 printAffineExprInternal(rhs.getLHS(), BindingStrength::Weak,
3111 if (enclosingTightness == BindingStrength::Strong)
3116 if (rrhs.getValue() < -1) {
3117 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
3120 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
3122 os <<
" * " << -rrhs.getValue();
3123 if (enclosingTightness == BindingStrength::Strong)
3132 if (
auto rhsConst = dyn_cast<AffineConstantExpr>(rhsExpr)) {
3133 if (rhsConst.getValue() < 0) {
3134 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
3135 os <<
" - " << -rhsConst.getValue();
3136 if (enclosingTightness == BindingStrength::Strong)
3142 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
3145 printAffineExprInternal(rhsExpr, BindingStrength::Weak, printValueName);
3147 if (enclosingTightness == BindingStrength::Strong)
3152 printAffineExprInternal(expr, BindingStrength::Weak);
3153 isEq ? os <<
" == 0" : os <<
" >= 0";
3159 for (
int i = 0; i < (int)map.
getNumDims() - 1; ++i)
3160 os <<
'd' << i <<
", ";
3169 os <<
's' << i <<
", ";
3178 [&](
AffineExpr expr) { printAffineExpr(expr); });
3185 for (
unsigned i = 1; i < set.
getNumDims(); ++i)
3186 os <<
'd' << i - 1 <<
", ";
3195 os <<
's' << i <<
", ";
3204 for (
int i = 1; i < numConstraints; ++i) {
3208 if (numConstraints >= 1)
3209 printAffineConstraint(set.
getConstraint(numConstraints - 1),
3210 set.
isEq(numConstraints - 1));
3225 explicit OperationPrinter(raw_ostream &os,
AsmStateImpl &state)
3229 void printTopLevelOperation(
Operation *op);
3233 void printFullOpWithIndentAndLoc(
Operation *op);
3239 void printCustomOrGenericOp(
Operation *op)
override;
3241 void printGenericOp(
Operation *op,
bool printOpName)
override;
3244 void printBlockName(
Block *block);
3249 void print(
Block *block,
bool printBlockArgs =
true,
3250 bool printBlockTerminator =
true);
3253 void printValueID(
Value value,
bool printResultNo =
true,
3254 raw_ostream *streamOverride =
nullptr)
const;
3258 raw_ostream *streamOverride =
nullptr)
const;
3266 void printOptionalLocationSpecifier(
Location loc)
override {
3267 printTrailingLocation(loc);
3274 os.indent(currentIndent);
3278 void increaseIndent()
override { currentIndent += indentWidth; }
3281 void decreaseIndent()
override { currentIndent -= indentWidth; }
3290 bool omitType =
false)
override;
3293 void printOperand(
Value value)
override { printValueID(value); }
3294 void printOperand(
Value value, raw_ostream &os)
override {
3295 printValueID(value,
true, &os);
3303 void printOptionalAttrDictWithKeyword(
3311 void printSuccessor(
Block *successor)
override;
3315 void printSuccessorAndUseList(
Block *successor,
3320 bool printBlockTerminators,
bool printEmptyBlock)
override;
3327 state.getSSANameState().shadowRegionArgs(region, namesToUse);
3332 void printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3347 void printValueUsers(
Value value);
3351 void printUserIDs(
Operation *user,
bool prefixComma =
false);
3359 using PrintFn =
function_ref<void(StringRef, ValueFn)>;
3361 ResourceBuilder(PrintFn printFn) : printFn(printFn) {}
3362 ~ResourceBuilder()
override =
default;
3364 void buildBool(StringRef key,
bool data)
final {
3365 printFn(key, [&](raw_ostream &os) { os << (data ?
"true" :
"false"); });
3368 void buildString(StringRef key, StringRef data)
final {
3369 printFn(key, [&](raw_ostream &os) {
3371 llvm::printEscapedString(data, os);
3377 uint32_t dataAlignment)
final {
3378 printFn(key, [&](raw_ostream &os) {
3380 llvm::support::ulittle32_t dataAlignmentLE(dataAlignment);
3382 << llvm::toHex(StringRef(
reinterpret_cast<char *
>(&dataAlignmentLE),
3383 sizeof(dataAlignment)))
3384 << llvm::toHex(StringRef(data.data(), data.size())) <<
"\"";
3393 void printFileMetadataDictionary(
Operation *op);
3399 void printResourceFileMetadata(
function_ref<
void()> checkAddMetadataDict,
3410 const static unsigned indentWidth = 2;
3413 unsigned currentIndent = 0;
3417 void OperationPrinter::printTopLevelOperation(
Operation *op) {
3419 state.getAliasState().printNonDeferredAliases(*
this, newLine);
3422 printFullOpWithIndentAndLoc(op);
3426 state.getAliasState().printDeferredAliases(*
this, newLine);
3429 printFileMetadataDictionary(op);
3432 void OperationPrinter::printFileMetadataDictionary(
Operation *op) {
3433 bool sawMetadataEntry =
false;
3434 auto checkAddMetadataDict = [&] {
3435 if (!std::exchange(sawMetadataEntry,
true))
3436 os << newLine <<
"{-#" << newLine;
3440 printResourceFileMetadata(checkAddMetadataDict, op);
3443 if (sawMetadataEntry)
3444 os << newLine <<
"#-}" << newLine;
3447 void OperationPrinter::printResourceFileMetadata(
3450 bool hadResource =
false;
3451 bool needResourceComma =
false;
3452 bool needEntryComma =
false;
3453 auto processProvider = [&](StringRef dictName, StringRef name,
auto &provider,
3454 auto &&...providerArgs) {
3455 bool hadEntry =
false;
3456 auto printFn = [&](StringRef key, ResourceBuilder::ValueFn valueFn) {
3457 checkAddMetadataDict();
3459 std::string resourceStr;
3460 auto printResourceStr = [&](raw_ostream &os) { os << resourceStr; };
3461 std::optional<uint64_t> charLimit =
3463 if (charLimit.has_value()) {
3465 if (charLimit.value() == 0)
3468 llvm::raw_string_ostream ss(resourceStr);
3472 if (resourceStr.size() > charLimit.value())
3476 valueFn = printResourceStr;
3480 if (!std::exchange(hadResource,
true)) {
3481 if (needResourceComma)
3482 os <<
"," << newLine;
3483 os <<
" " << dictName <<
"_resources: {" << newLine;
3486 if (!std::exchange(hadEntry,
true)) {
3488 os <<
"," << newLine;
3489 os <<
" " << name <<
": {" << newLine;
3491 os <<
"," << newLine;
3499 ResourceBuilder entryBuilder(printFn);
3500 provider.buildResources(op, providerArgs..., entryBuilder);
3502 needEntryComma |= hadEntry;
3504 os << newLine <<
" }";
3510 auto &dialectResources = state.getDialectResources();
3511 StringRef name = interface.getDialect()->getNamespace();
3512 auto it = dialectResources.find(interface.getDialect());
3513 if (it != dialectResources.end())
3514 processProvider(
"dialect", name, interface, it->second);
3516 processProvider(
"dialect", name, interface,
3520 os << newLine <<
" }";
3524 needEntryComma =
false;
3525 needResourceComma = hadResource;
3526 hadResource =
false;
3527 for (
const auto &printer : state.getResourcePrinters())
3528 processProvider(
"external", printer.getName(), printer);
3530 os << newLine <<
" }";
3538 void OperationPrinter::printRegionArgument(
BlockArgument arg,
3546 printOptionalAttrDict(argAttrs);
3548 printTrailingLocation(arg.
getLoc(),
false);
3551 void OperationPrinter::printFullOpWithIndentAndLoc(
Operation *op) {
3553 state.registerOperationLocation(op, newLine.curLine, currentIndent);
3555 os.indent(currentIndent);
3557 printTrailingLocation(op->
getLoc());
3559 printUsersComment(op);
3562 void OperationPrinter::printFullOp(
Operation *op) {
3564 auto printResultGroup = [&](
size_t resultNo,
size_t resultCount) {
3565 printValueID(op->
getResult(resultNo),
false);
3566 if (resultCount > 1)
3567 os <<
':' << resultCount;
3571 ArrayRef<int> resultGroups = state.getSSANameState().getOpResultGroups(op);
3572 if (!resultGroups.empty()) {
3575 interleaveComma(llvm::seq<int>(0, resultGroups.size() - 1), [&](
int i) {
3576 printResultGroup(resultGroups[i],
3577 resultGroups[i + 1] - resultGroups[i]);
3580 printResultGroup(resultGroups.back(), numResults - resultGroups.back());
3583 printResultGroup(0, numResults);
3589 printCustomOrGenericOp(op);
3592 void OperationPrinter::printUsersComment(
Operation *op) {
3596 printOperationID(op);
3597 }
else if (numResults && op->
use_empty()) {
3599 }
else if (numResults && !op->
use_empty()) {
3602 unsigned usedInNResults = 0;
3603 unsigned usedInNOperations = 0;
3606 if (userSet.insert(user).second) {
3607 ++usedInNOperations;
3608 usedInNResults += user->getNumResults();
3613 bool exactlyOneUniqueUse =
3614 usedInNResults <= 1 && usedInNOperations <= 1 && numResults == 1;
3615 os <<
" // " << (exactlyOneUniqueUse ?
"user" :
"users") <<
": ";
3616 bool shouldPrintBrackets = numResults > 1;
3617 auto printOpResult = [&](
OpResult opResult) {
3618 if (shouldPrintBrackets)
3620 printValueUsers(opResult);
3621 if (shouldPrintBrackets)
3625 interleaveComma(op->
getResults(), printOpResult);
3629 void OperationPrinter::printUsersComment(
BlockArgument arg) {
3635 os <<
" is used by ";
3636 printValueUsers(arg);
3641 void OperationPrinter::printValueUsers(
Value value) {
3649 if (userSet.insert(user).second)
3650 printUserIDs(user, index);
3654 void OperationPrinter::printUserIDs(
Operation *user,
bool prefixComma) {
3659 printOperationID(user);
3662 [
this](
Value result) { printValueID(result); });
3666 void OperationPrinter::printCustomOrGenericOp(
Operation *op) {
3672 opInfo->printAssembly(op, *
this, defaultDialectStack.back());
3677 if (
auto opPrinter = dialect->getOperationPrinter(op)) {
3682 if (name.count(
'.') == 1)
3683 name.consume_front((defaultDialectStack.back() +
".").str());
3687 opPrinter(op, *
this);
3694 printGenericOp(op,
true);
3697 void OperationPrinter::printGenericOp(
Operation *op,
bool printOpName) {
3701 interleaveComma(op->
getOperands(), [&](
Value value) { printValueID(value); });
3708 [&](
Block *successor) { printBlockName(successor); });
3720 if (op->getNumRegions() != 0) {
3722 interleaveComma(op->getRegions(), [&](Region ®ion) {
3723 printRegion(region, /*printEntryBlockArgs=*/true,
3724 /*printBlockTerminators=*/true, /*printEmptyBlock=*/true);
3729 printOptionalAttrDict(op->getPropertiesStorage()
3730 ? llvm::to_vector(op->getDiscardableAttrs())
3733 // Print the type signature of the operation.
3735 printFunctionalType(op);
3738 void OperationPrinter::printBlockName(Block *block) {
3739 os << state.getSSANameState().getBlockInfo(block).name;
3742 void OperationPrinter::print(Block *block, bool printBlockArgs,
3743 bool printBlockTerminator) {
3744 // Print the block label and argument list if requested.
3745 if (printBlockArgs) {
3746 os.indent(currentIndent);
3747 printBlockName(block);
3749 // Print the argument list if non-empty.
3750 if (!block->args_empty()) {
3752 interleaveComma(block->getArguments(), [&](BlockArgument arg) {
3755 printType(arg.getType());
3756 // TODO: We should allow location aliases on block arguments.
3757 printTrailingLocation(arg.getLoc(), /*allowAlias*/ false);
3763 // Print out some context information about the predecessors of this block.
3764 if (!block->getParent()) {
3765 os << " // block is not in a region!";
3766 } else if (block->hasNoPredecessors()) {
3767 if (!block->isEntryBlock())
3768 os << " // no predecessors";
3769 } else if (auto *pred = block->getSinglePredecessor()) {
3771 printBlockName(pred);
3773 // We want to print the predecessors in a stable order, not in
3774 // whatever order the use-list is in, so gather and sort them.
3775 SmallVector<BlockInfo, 4> predIDs;
3776 for (auto *pred : block->getPredecessors())
3777 predIDs.push_back(state.getSSANameState().getBlockInfo(pred));
3778 llvm::sort(predIDs, [](BlockInfo lhs, BlockInfo rhs) {
3779 return lhs.ordering < rhs.ordering;
3782 os << " // " << predIDs.size() << " preds: ";
3784 interleaveComma(predIDs, [&](BlockInfo pred) { os << pred.name; });
3789 currentIndent += indentWidth;
3791 if (printerFlags.shouldPrintValueUsers()) {
3792 for (BlockArgument arg : block->getArguments()) {
3793 os.indent(currentIndent);
3794 printUsersComment(arg);
3798 bool hasTerminator =
3799 !block->empty() && block->back().hasTrait<OpTrait::IsTerminator>();
3800 auto range = llvm::make_range(
3802 std::prev(block->end(),
3803 (!hasTerminator || printBlockTerminator) ? 0 : 1));
3804 for (auto &op : range) {
3805 printFullOpWithIndentAndLoc(&op);
3808 currentIndent -= indentWidth;
3811 void OperationPrinter::printValueID(Value value, bool printResultNo,
3812 raw_ostream *streamOverride) const {
3813 state.getSSANameState().printValueID(value, printResultNo,
3814 streamOverride ? *streamOverride : os);
3817 void OperationPrinter::printOperationID(Operation *op,
3818 raw_ostream *streamOverride) const {
3819 state.getSSANameState().printOperationID(op, streamOverride ? *streamOverride
3823 void OperationPrinter::printSuccessor(Block *successor) {
3824 printBlockName(successor);
3827 void OperationPrinter::printSuccessorAndUseList(Block *successor,
3828 ValueRange succOperands) {
3829 printBlockName(successor);
3830 if (succOperands.empty())
3834 interleaveComma(succOperands,
3835 [this](Value operand) { printValueID(operand); });
3837 interleaveComma(succOperands,
3838 [this](Value operand) { printType(operand.getType()); });
3842 void OperationPrinter::printRegion(Region ®ion, bool printEntryBlockArgs,
3843 bool printBlockTerminators,
3844 bool printEmptyBlock) {
3845 if (printerFlags.shouldSkipRegions()) {
3849 os << "{" << newLine;
3850 if (!region.empty()) {
3851 auto restoreDefaultDialect =
3852 llvm::make_scope_exit([&]() { defaultDialectStack.pop_back(); });
3853 if (auto iface = dyn_cast<OpAsmOpInterface>(region.getParentOp()))
3854 defaultDialectStack.push_back(iface.getDefaultDialect());
3856 defaultDialectStack.push_back("");
3858 auto *entryBlock = ®ion.front();
3859 // Force printing the block header if printEmptyBlock is set and the block
3860 // is empty or if printEntryBlockArgs is set and there are arguments to
3862 bool shouldAlwaysPrintBlockHeader =
3863 (printEmptyBlock && entryBlock->empty()) ||
3864 (printEntryBlockArgs && entryBlock->getNumArguments() != 0);
3865 print(entryBlock, shouldAlwaysPrintBlockHeader, printBlockTerminators);
3866 for (auto &b : llvm::drop_begin(region.getBlocks(), 1))
3869 os.indent(currentIndent) << "}";
3872 void OperationPrinter::printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3873 ValueRange operands) {
3875 os << "<<NULL AFFINE MAP>>";
3878 AffineMap map = mapAttr.getValue();
3879 unsigned numDims = map.getNumDims();
3880 auto printValueName = [&](unsigned pos, bool isSymbol) {
3881 unsigned index = isSymbol ? numDims + pos : pos;
3882 assert(index < operands.size());
3885 printValueID(operands[index]);
3890 interleaveComma(map.getResults(), [&](AffineExpr expr) {
3891 printAffineExpr(expr, printValueName);
3895 void OperationPrinter::printAffineExprOfSSAIds(AffineExpr expr,
3896 ValueRange dimOperands,
3897 ValueRange symOperands) {
3898 auto printValueName = [&](unsigned pos, bool isSymbol) {
3900 return printValueID(dimOperands[pos]);
3902 printValueID(symOperands[pos]);
3905 printAffineExpr(expr, printValueName);
3908 //===----------------------------------------------------------------------===//
3909 // print and dump methods
3910 //===----------------------------------------------------------------------===//
3912 void Attribute::print(raw_ostream &os, bool elideType) const {
3914 os << "<<NULL ATTRIBUTE>>";
3918 AsmState state(getContext());
3919 print(os, state, elideType);
3921 void Attribute::print(raw_ostream &os, AsmState &state, bool elideType) const {
3922 using AttrTypeElision = AsmPrinter::Impl::AttrTypeElision;
3923 AsmPrinter::Impl(os, state.getImpl())
3924 .printAttribute(*this, elideType ? AttrTypeElision::Must
3925 : AttrTypeElision::Never);
3928 void Attribute::dump() const {
3929 print(llvm::errs());
3930 llvm::errs() << "\n";
3933 void Attribute::printStripped(raw_ostream &os, AsmState &state) const {
3935 os << "<<NULL ATTRIBUTE>>";
3939 AsmPrinter::Impl subPrinter(os, state.getImpl());
3940 if (succeeded(subPrinter.printAlias(*this)))
3943 auto &dialect = this->getDialect();
3944 uint64_t posPrior = os.tell();
3945 DialectAsmPrinter printer(subPrinter);
3946 dialect.printAttribute(*this, printer);
3947 if (posPrior != os.tell())
3950 // Fallback to printing with prefix if the above failed to write anything
3951 // to the output stream.
3954 void Attribute::printStripped(raw_ostream &os) const {
3956 os << "<<NULL ATTRIBUTE>>";
3960 AsmState state(getContext());
3961 printStripped(os, state);
3964 void Type::print(raw_ostream &os) const {
3966 os << "<<NULL TYPE>>";
3970 AsmState state(getContext());
3973 void Type::print(raw_ostream &os, AsmState &state) const {
3974 AsmPrinter::Impl(os, state.getImpl()).printType(*this);
3977 void Type::dump() const {
3978 print(llvm::errs());
3979 llvm::errs() << "\n";
3982 void AffineMap::dump() const {
3983 print(llvm::errs());
3984 llvm::errs() << "\n";
3987 void IntegerSet::dump() const {
3988 print(llvm::errs());
3989 llvm::errs() << "\n";
3992 void AffineExpr::print(raw_ostream &os) const {
3994 os << "<<NULL AFFINE EXPR>>";
3997 AsmState state(getContext());
3998 AsmPrinter::Impl(os, state.getImpl()).printAffineExpr(*this);
4001 void AffineExpr::dump() const {
4002 print(llvm::errs());
4003 llvm::errs() << "\n";
4006 void AffineMap::print(raw_ostream &os) const {
4008 os << "<<NULL AFFINE MAP>>";
4011 AsmState state(getContext());
4012 AsmPrinter::Impl(os, state.getImpl()).printAffineMap(*this);
4015 void IntegerSet::print(raw_ostream &os) const {
4016 AsmState state(getContext());
4017 AsmPrinter::Impl(os, state.getImpl()).printIntegerSet(*this);
4020 void Value::print(raw_ostream &os) const { print(os, OpPrintingFlags()); }
4021 void Value::print(raw_ostream &os, const OpPrintingFlags &flags) const {
4023 os << "<<NULL VALUE>>";
4027 if (auto *op = getDefiningOp())
4028 return op->print(os, flags);
4029 // TODO: Improve BlockArgument print'ing.
4031 os <<
"<block argument> of type '" << arg.
getType()
4036 os <<
"<<NULL VALUE>>";
4040 if (
auto *op = getDefiningOp())
4041 return op->
print(os, state);
4045 os <<
"<block argument> of type '" << arg.
getType()
4050 print(llvm::errs());
4051 llvm::errs() <<
"\n";
4059 state.getImpl().getSSANameState().printValueID(*
this,
true,
4082 if (
auto result = llvm::dyn_cast<OpResult>(*
this)) {
4085 op = llvm::cast<BlockArgument>(*this).getOwner()->
getParentOp();
4087 os <<
"<<UNKNOWN SSA VALUE>>";
4093 printAsOperand(os, state);
4103 OperationPrinter printer(os, state.getImpl());
4104 if (!getParent() && !state.getPrinterFlags().shouldUseLocalScope()) {
4105 state.getImpl().initializeAliases(
this);
4106 printer.printTopLevelOperation(
this);
4108 printer.printFullOpWithIndentAndLoc(
this);
4114 llvm::errs() <<
"\n";
4119 llvm::errs() <<
"\n";
4125 os <<
"<<UNLINKED BLOCK>>\n";
4136 OperationPrinter(os, state.getImpl()).print(
this);
4145 os <<
"<<UNLINKED BLOCK>>\n";
4149 printAsOperand(os, state);
4152 OperationPrinter printer(os, state.getImpl());
4153 printer.printBlockName(
this);
4168 if (dimensions.empty())
4171 if (dimensions.empty())
4181 <<
"Failed parsing dimension list.";
4192 <<
"Failed parsing dimension list.";
4194 if (shapeArr.empty()) {
4196 <<
"Failed parsing dimension list. Did you mean an empty list? It "
4197 "must be denoted by \"[]\".";
static void printSymbolReference(StringRef symbolRef, raw_ostream &os)
Print the given string as a symbol reference.
static void printFloatValue(const APFloat &apValue, raw_ostream &os, bool *printedHex=nullptr)
Print a floating point value in a way that the parser will be able to round-trip losslessly.
static StringRef sanitizeIdentifier(StringRef name, SmallString< 16 > &buffer, StringRef allowedPunctChars="$._-")
Sanitize the given name such that it can be used as a valid identifier.
static llvm::ManagedStatic< AsmPrinterOptions > clOptions
static Operation * findParent(Operation *op, bool shouldUseLocalScope)
static void printKeywordOrString(StringRef keyword, raw_ostream &os)
Print the given string as a keyword, or a quoted and escaped string if it has any special or non-prin...
static bool isDialectSymbolSimpleEnoughForPrettyForm(StringRef symName)
Returns true if the given dialect symbol data is simple enough to print in the pretty form.
static void printDialectSymbol(raw_ostream &os, StringRef symPrefix, StringRef dialectName, StringRef symString)
Print the given dialect symbol to the stream.
static OpPrintingFlags verifyOpAndAdjustFlags(Operation *op, OpPrintingFlags printerFlags)
Verifies the operation and switches to generic op printing if verification fails.
MLIR_CRUNNERUTILS_EXPORT void printString(char const *s)
MLIR_CRUNNERUTILS_EXPORT void printNewline()
static void visit(Operation *op, DenseSet< Operation * > &visited)
Visits all the pdl.operand(s), pdl.result(s), and pdl.operation(s) connected to the given operation.
static MLIRContext * getContext(OpFoldResult val)
union mlir::linalg::@1200::ArityGroupAndKind::Kind kind
static std::string diag(const llvm::Value &value)
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
static void printRegion(llvm::raw_ostream &os, Region *region, OpPrintingFlags &flags)
Base type for affine expression.
AffineExprKind getKind() const
Return the classification for this type.
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
unsigned getNumSymbols() const
unsigned getNumDims() const
ArrayRef< AffineExpr > getResults() const
This class represents an opaque handle to a dialect resource entry.
This class represents a single parsed resource entry.
virtual FailureOr< AsmResourceBlob > parseAsBlob(BlobAllocatorFn allocator) const =0
Parse the resource entry represented by a binary blob.
virtual InFlightDiagnostic emitError() const =0
Emit an error at the location of this entry.
virtual AsmResourceEntryKind getKind() const =0
Return the kind of this value.
virtual FailureOr< std::string > parseAsString() const =0
Parse the resource entry represented by a human-readable string.
virtual FailureOr< bool > parseAsBool() const =0
Parse the resource entry represented by a boolean.
virtual StringRef getKey() const =0
Return the key of the resource entry.
MLIRContext * getContext() const
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
virtual ParseResult parseRSquare()=0
Parse a ] token.
virtual ParseResult parseDimensionList(SmallVectorImpl< int64_t > &dimensions, bool allowDynamic=true, bool withTrailingX=true)=0
Parse a dimension list of a tensor or memref type.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
ParseResult parseTypeList(SmallVectorImpl< Type > &result)
Parse a type list.
virtual ParseResult parseOptionalLSquare()=0
Parse a [ token if present.
Impl(raw_ostream &os, AsmStateImpl &state)
BindingStrength
This enum is used to represent the binding strength of the enclosing context that an AffineExprStorag...
void printHexString(StringRef str)
Print a hex string, wrapped with "".
void printDenseArrayAttr(DenseArrayAttr attr)
Print a dense array attribute.
void printDenseElementsAttr(DenseElementsAttr attr, bool allowHex)
Print a dense elements attribute.
void printAttribute(Attribute attr, AttrTypeElision typeElision=AttrTypeElision::Never)
Print the given attribute or an alias.
void printDimensionList(ArrayRef< int64_t > shape)
OpPrintingFlags printerFlags
A set of flags to control the printer's behavior.
raw_ostream & os
The output stream for the printer.
void printResourceHandle(const AsmDialectResourceHandle &resource)
Print a reference to the given resource that is owned by the given dialect.
raw_ostream & getStream()
Returns the output stream of the printer.
LogicalResult printAlias(Attribute attr)
Print the alias for the given attribute, return failure if no alias could be printed.
void printDialectAttribute(Attribute attr)
void interleaveComma(const Container &c, UnaryFunctor eachFn) const
void printDialectType(Type type)
void printLocation(LocationAttr loc, bool allowAlias=false)
Print the given location to the stream.
AsmStateImpl & state
An underlying assembly printer state.
void printAffineMap(AffineMap map)
void printTrailingLocation(Location loc, bool allowAlias=true)
void printAffineExprInternal(AffineExpr expr, BindingStrength enclosingTightness, function_ref< void(unsigned, bool)> printValueName=nullptr)
void printEscapedString(StringRef str)
Print an escaped string, wrapped with "".
void printAffineExpr(AffineExpr expr, function_ref< void(unsigned, bool)> printValueName=nullptr)
void printDenseStringElementsAttr(DenseStringElementsAttr attr)
Print a dense string elements attribute.
void printAttributeImpl(Attribute attr, AttrTypeElision typeElision=AttrTypeElision::Never)
Print the given attribute without considering an alias.
void printAffineConstraint(AffineExpr expr, bool isEq)
void printDenseIntOrFPElementsAttr(DenseIntOrFPElementsAttr attr, bool allowHex)
Print a dense elements attribute.
AttrTypeElision
This enum describes the different kinds of elision for the type of an attribute when printing it.
@ May
The type may be elided when it matches the default used in the parser (for example i64 is the default...
@ Never
The type must not be elided,.
@ Must
The type must be elided.
LogicalResult pushCyclicPrinting(const void *opaquePointer)
void printIntegerSet(IntegerSet set)
NewLineCounter newLine
A tracker for the number of new lines emitted during printing.
void printOptionalAttrDict(ArrayRef< NamedAttribute > attrs, ArrayRef< StringRef > elidedAttrs={}, bool withKeyword=false)
void printType(Type type)
Print the given type or an alias.
void printLocationInternal(LocationAttr loc, bool pretty=false, bool isTopLevel=false)
void printTypeImpl(Type type)
Print the given type.
void printNamedAttribute(NamedAttribute attr)
virtual void printAttributeWithoutType(Attribute attr)
Print the given attribute without its type.
virtual LogicalResult printAlias(Attribute attr)
Print the alias for the given attribute, return failure if no alias could be printed.
virtual void popCyclicPrinting()
Removes the element that was last inserted with a successful call to pushCyclicPrinting.
virtual LogicalResult pushCyclicPrinting(const void *opaquePointer)
Pushes a new attribute or type in the form of a type erased pointer into an internal set.
virtual void printType(Type type)
virtual void printKeywordOrString(StringRef keyword)
Print the given string as a keyword, or a quoted and escaped string if it has any special or non-prin...
virtual void printSymbolName(StringRef symbolRef)
Print the given string as a symbol reference, i.e.
virtual void printString(StringRef string)
Print the given string as a quoted string, escaping any special or non-printable characters in it.
virtual void printAttribute(Attribute attr)
void printDimensionList(ArrayRef< int64_t > shape)
virtual raw_ostream & getStream() const
Return the raw output stream used by this printer.
virtual void printResourceHandle(const AsmDialectResourceHandle &resource)
Print a handle to the given dialect resource.
virtual void printFloat(const APFloat &value)
Print the given floating point value in a stabilized form that can be roundtripped through the IR.
This class is used to build resource entries for use by the printer.
virtual void buildString(StringRef key, StringRef data)=0
Build a resource entry represented by the given human-readable string value.
virtual void buildBool(StringRef key, bool data)=0
Build a resource entry represented by the given bool.
virtual void buildBlob(StringRef key, ArrayRef< char > data, uint32_t dataAlignment)=0
Build an resource entry represented by the given binary blob data.
This class represents an instance of a resource parser.
static std::unique_ptr< AsmResourcePrinter > fromCallable(StringRef name, CallableT &&printFn)
Return a resource printer implemented via the given callable, whose form should match that of buildRe...
This class provides management for the lifetime of the state used when printing the IR.
void attachResourcePrinter(std::unique_ptr< AsmResourcePrinter > printer)
Attach the given resource printer to the AsmState.
DenseMap< Dialect *, SetVector< AsmDialectResourceHandle > > & getDialectResources() const
Returns a map of dialect resources that were referenced when using this state to print IR.
void attachFallbackResourcePrinter(FallbackAsmResourceMap &map)
Attach resource printers to the AsmState for the fallback resources in the given map.
const OpPrintingFlags & getPrinterFlags() const
Get the printer flags.
Attributes are known-constant values of operations.
Dialect & getDialect() const
Get the dialect this attribute is registered to.
bool hasTrait()
Returns true if the type was registered with a particular trait.
const void * getAsOpaquePointer() const
Get an opaque pointer to the attribute.
static Attribute getFromOpaquePointer(const void *ptr)
Construct an attribute from the opaque pointer representation.
This class represents an argument of a Block.
Location getLoc() const
Return the location for this argument.
unsigned getArgNumber() const
Returns the number of this argument.
Block represents an ordered list of Operations.
void printAsOperand(raw_ostream &os, bool printType=true)
Print out the name of the block without printing its body.
void print(raw_ostream &os)
BlockArgListType getArguments()
bool isEntryBlock()
Return if this block is the entry block in the parent region.
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
An attribute that represents a reference to a dense vector or tensor object.
This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine.
~DialectAsmParser() override
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
~DialectAsmPrinter() override
A collection of dialect interfaces within a context, for a given concrete interface type.
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
virtual void printAttribute(Attribute, DialectAsmPrinter &) const
Print an attribute registered to this dialect.
virtual void printType(Type, DialectAsmPrinter &) const
Print a type registered to this dialect.
An attribute that associates a referenced attribute with a unique identifier.
A fallback map containing external resources not explicitly handled by another parser/printer.
std::vector< std::unique_ptr< AsmResourcePrinter > > getPrinters()
Build a set of resource printers to print the resources within this map.
An integer set representing a conjunction of one or more affine equalities and inequalities.
unsigned getNumDims() const
unsigned getNumConstraints() const
AffineExpr getConstraint(unsigned idx) const
bool isEq(unsigned idx) const
Returns true if the idx^th constraint is an equality, false if it is an inequality.
unsigned getNumSymbols() const
Location objects represent source locations information in MLIR.
T findInstanceOf()
Return an instance of the given location type if one is nested under the current location.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
NamedAttribute represents a combination of a name and an Attribute value.
Attribute getValue() const
Return the value of the attribute.
virtual LogicalResult parseResource(AsmParsedResourceEntry &entry) const
Hook for parsing resource entries.
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
void printFunctionalType(Operation *op)
Print the complete type of an operation in functional form.
Set of flags used to control the behavior of the various IR print methods (e.g.
bool shouldElideElementsAttr(ElementsAttr attr) const
Return if the given ElementsAttr should be elided.
std::optional< int64_t > getLargeElementsAttrLimit() const
Return the size limit for printing large ElementsAttr.
bool shouldUseNameLocAsPrefix() const
Return if the printer should use NameLocs as prefixes when printing SSA IDs.
bool shouldAssumeVerified() const
Return if operation verification should be skipped.
OpPrintingFlags & printLargeElementsAttrWithHex(int64_t largeElementLimit=100)
Enables the printing of large element attributes with a hex string.
bool shouldUseLocalScope() const
Return if the printer should use local scope when dumping the IR.
bool shouldPrintDebugInfoPrettyForm() const
Return if debug information should be printed in the pretty form.
bool shouldPrintElementsAttrWithHex(ElementsAttr attr) const
Return if the given ElementsAttr should be printed as hex string.
bool shouldPrintUniqueSSAIDs() const
Return if printer should use unique SSA IDs.
bool shouldPrintValueUsers() const
Return if the printer should print users of values.
int64_t getLargeElementsAttrHexLimit() const
Return the size limit for printing large ElementsAttr as hex string.
bool shouldPrintGenericOpForm() const
Return if operations should be printed in the generic form.
OpPrintingFlags & elideLargeResourceString(int64_t largeResourceLimit=64)
Enables the elision of large resources strings by omitting them from the dialect_resources section.
bool shouldPrintDebugInfo() const
Return if debug information should be printed.
OpPrintingFlags & elideLargeElementsAttrs(int64_t largeElementLimit=16)
Enables the elision of large elements attributes by printing a lexically valid but otherwise meaningl...
OpPrintingFlags & printNameLocAsPrefix(bool enable=true)
Print SSA IDs using their NameLoc, if provided, as prefix.
OpPrintingFlags & printValueUsers(bool enable=true)
Print users of values as comments.
OpPrintingFlags & enableDebugInfo(bool enable=true, bool prettyForm=false)
Enable or disable printing of debug information (based on enable).
OpPrintingFlags()
Initialize the printing flags with default supplied by the cl::opts above.
bool shouldSkipRegions() const
Return if regions should be skipped.
OpPrintingFlags & printGenericOpForm(bool enable=true)
Always print operations in the generic form.
OpPrintingFlags & useLocalScope(bool enable=true)
Use local scope when printing the operation.
std::optional< uint64_t > getLargeResourceStringLimit() const
Return the size limit in chars for printing large resources.
OpPrintingFlags & assumeVerified(bool enable=true)
Do not verify the operation when using custom operation printers.
OpPrintingFlags & skipRegions(bool skip=true)
Skip printing regions.
OpPrintingFlags & printUniqueSSAIDs(bool enable=true)
Print unique SSA ID numbers for values, block arguments and naming conflicts across all regions.
This is a value defined by a result of an operation.
Operation * getOwner() const
Returns the operation that owns this result.
unsigned getResultNumber() const
Returns the number of this result.
This class provides the API for ops that are known to be isolated from above.
This class provides the API for ops that are known to be terminators.
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
void printAssembly(Operation *op, OpAsmPrinter &p, StringRef defaultDialect) const
This hook implements the AsmPrinter for this operation.
void print(raw_ostream &os) const
Operation is the basic unit of execution within MLIR.
bool use_empty()
Returns true if this operation has no uses.
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
Dialect * getDialect()
Return the dialect this operation is associated with, or nullptr if the associated dialect is not loa...
unsigned getNumSuccessors()
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
void print(raw_ostream &os, const OpPrintingFlags &flags=std::nullopt)
MLIRContext * getContext()
Return the context this operation is associated with.
std::optional< RegisteredOperationName > getRegisteredInfo()
If this operation has a registered operation description, return it.
Location getLoc()
The source location the operation was defined or derived from.
unsigned getNumOperands()
Attribute getPropertiesAsAttribute()
Return the properties converted to an attribute.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
ArrayRef< NamedAttribute > getAttrs()
Return all of the attributes on this operation.
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
OperationName getName()
The name of an operation is the key identifier for it.
operand_type_range getOperandTypes()
result_type_range getResultTypes()
LLVM_DUMP_METHOD void dumpPretty()
operand_range getOperands()
Returns an iterator on the underlying Value's.
user_range getUsers()
Returns a range of all users.
SuccessorRange getSuccessors()
result_range getResults()
unsigned getNumResults()
Return the number of results held by this operation.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
iterator_range< OpIterator > getOps()
BlockArgListType getArguments()
Operation * getParentOp()
Return the parent operation this region is attached to.
unsigned getNumArguments()
BlockArgument getArgument(unsigned i)
This diagnostic handler is a simple RAII class that registers and erases a diagnostic handler on a gi...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
const void * getAsOpaquePointer() const
Methods for supporting PointerLikeTypeTraits.
Dialect & getDialect() const
Get the dialect this type is registered to.
static Type getFromOpaquePointer(const void *pointer)
void walkImmediateSubElements(function_ref< void(Attribute)> walkAttrsFn, function_ref< void(Type)> walkTypesFn) const
Walk all of the immediately nested sub-attributes and sub-types.
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
bool use_empty() const
Returns true if this value has no uses.
void print(raw_ostream &os) const
Type getType() const
Return the type of this value.
void printAsOperand(raw_ostream &os, AsmState &state) const
Print this value as if it were an operand.
user_range getUsers() const
Location getLoc() const
Return the location of this value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
void registerOperationLocation(Operation *op, unsigned line, unsigned col)
Register the location, line and column, within the buffer that the given operation was printed at.
const OpPrintingFlags & getPrinterFlags() const
Get the printer flags.
auto getResourcePrinters()
Return the non-dialect resource printers.
LogicalResult pushCyclicPrinting(const void *opaquePointer)
SSANameState & getSSANameState()
Get the state used for SSA names.
DialectInterfaceCollection< OpAsmDialectInterface > & getDialectInterfaces()
Return the dialects within the context that implement OpAsmDialectInterface.
AliasState & getAliasState()
Get the state used for aliases.
void initializeAliases(Operation *op)
Initialize the alias state to enable the printing of aliases.
AsmStateImpl(Operation *op, const OpPrintingFlags &printerFlags, AsmState::LocationMap *locationMap)
DenseMap< Dialect *, SetVector< AsmDialectResourceHandle > > & getDialectResources()
Return the referenced dialect resources within the printer.
AsmStateImpl(MLIRContext *ctx, const OpPrintingFlags &printerFlags, AsmState::LocationMap *locationMap)
DistinctState & getDistinctState()
Get the state used for distinct attribute identifiers.
Base class for DenseArrayAttr that is instantiated and specialized for each supported element type be...
static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef< T > content)
Builder from ArrayRef<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)
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
OpAsmAliasResult
Holds the result of OpAsm{Dialect,Attr,Type}Interface::getAlias hook call.
@ NoAlias
The object (type or attribute) is not supported by the hook and an alias was not provided.
@ CeilDiv
RHS of ceildiv is always a constant or a symbolic expression.
@ Mul
RHS of mul is always a constant or a symbolic expression.
@ Mod
RHS of mod is always a constant or a symbolic expression with a positive value.
@ DimId
Dimensional identifier.
@ FloorDiv
RHS of floordiv is always a constant or a symbolic expression.
@ Constant
Constant integer.
@ SymbolId
Symbolic identifier.
void registerAsmPrinterCLOptions()
Register a set of useful command-line options that can be used to configure various flags within the ...
Type parseType(llvm::StringRef typeStr, MLIRContext *context, size_t *numRead=nullptr, bool isKnownNullTerminated=false)
This parses a single MLIR type to an MLIR context if it was valid.
AsmResourceEntryKind
This enum represents the different kinds of resource values.
@ Blob
A blob of data with an accompanying alignment.
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
raw_ostream & operator<<(raw_ostream &os, const AliasResult &result)
Represents a range (offset, size, and stride) where each element of the triple may be dynamic or stat...
This trait is used to determine if a storage user, like Type, is mutable or not.