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] = aliases.try_emplace(value.getAsOpaquePointer());
1150 size_t aliasIndex = std::distance(aliases.begin(), it);
1154 markAliasNonDeferrable(aliasIndex);
1155 return {
static_cast<size_t>(it->second.aliasDepth), aliasIndex};
1159 generateAlias(value, it->second, canBeDeferred);
1160 it->second.isType = std::is_base_of_v<Type, T>;
1161 it->second.canBeDeferred = canBeDeferred;
1165 DummyAliasDialectAsmPrinter printer(*
this, canBeDeferred, childAliases);
1166 size_t maxAliasDepth =
1167 printer.printAndVisitNestedAliases(value, printArgs...);
1170 it = std::next(aliases.begin(), aliasIndex);
1173 it->second.childIndices = std::move(childAliases);
1175 it->second.aliasDepth = maxAliasDepth + 1;
1178 return {(size_t)it->second.aliasDepth, aliasIndex};
1181 void AliasInitializer::markAliasNonDeferrable(
size_t aliasIndex) {
1182 auto *it = std::next(aliases.begin(), aliasIndex);
1186 if (!it->second.canBeDeferred)
1189 it->second.canBeDeferred =
false;
1192 for (
size_t childIndex : it->second.childIndices)
1193 markAliasNonDeferrable(childIndex);
1196 template <
typename T>
1197 void AliasInitializer::generateAlias(T symbol, InProgressAliasInfo &alias,
1198 bool canBeDeferred) {
1203 using InterfaceT = std::conditional_t<std::is_base_of_v<Attribute, T>,
1204 OpAsmAttrInterface, OpAsmTypeInterface>;
1205 if (
auto symbolInterface = dyn_cast<InterfaceT>(symbol)) {
1206 symbolInterfaceResult = symbolInterface.getAlias(aliasOS);
1208 nameBuffer = std::move(aliasBuffer);
1209 assert(!nameBuffer.empty() &&
"expected valid alias name");
1213 if (symbolInterfaceResult != OpAsmDialectInterface::AliasResult::FinalAlias) {
1214 for (
const auto &interface : interfaces) {
1216 interface.getAlias(symbol, aliasOS);
1219 nameBuffer = std::move(aliasBuffer);
1220 assert(!nameBuffer.empty() &&
"expected valid alias name");
1221 if (result == OpAsmDialectInterface::AliasResult::FinalAlias)
1226 if (nameBuffer.empty())
1232 name = name.copy(aliasAllocator);
1233 alias = InProgressAliasInfo(name);
1251 LogicalResult getAlias(
Attribute attr, raw_ostream &os)
const;
1255 LogicalResult getAlias(
Type ty, raw_ostream &os)
const;
1259 void printNonDeferredAliases(
AsmPrinter::Impl &p, NewLineCounter &newLine) {
1260 printAliases(p, newLine,
false);
1265 printAliases(p, newLine,
true);
1275 llvm::MapVector<const void *, SymbolAlias> attrTypeToAlias;
1278 llvm::BumpPtrAllocator aliasAllocator;
1282 void AliasState::initialize(
1285 AliasInitializer initializer(interfaces, aliasAllocator);
1286 initializer.initialize(op, printerFlags, attrTypeToAlias);
1289 LogicalResult AliasState::getAlias(
Attribute attr, raw_ostream &os)
const {
1291 if (it == attrTypeToAlias.end())
1293 it->second.print(os);
1297 LogicalResult AliasState::getAlias(
Type ty, raw_ostream &os)
const {
1299 if (it == attrTypeToAlias.end())
1301 if (!it->second.isPrinted)
1304 it->second.print(os);
1308 void AliasState::printAliases(
AsmPrinter::Impl &p, NewLineCounter &newLine,
1310 auto filterFn = [=](
const auto &aliasIt) {
1311 return aliasIt.second.canBeDeferred() == isDeferred;
1313 for (
auto &[opaqueSymbol, alias] :
1314 llvm::make_filter_range(attrTypeToAlias, filterFn)) {
1318 if (alias.isTypeAlias()) {
1321 alias.isPrinted =
true;
1348 class SSANameState {
1351 enum :
unsigned { NameSentinel = ~0U };
1354 SSANameState() =
default;
1359 void printValueID(
Value value,
bool printResultNo, raw_ostream &stream)
const;
1362 void printOperationID(
Operation *op, raw_ostream &stream)
const;
1369 BlockInfo getBlockInfo(
Block *block);
1378 void numberValuesInRegion(
Region ®ion);
1379 void numberValuesInBlock(
Block &block);
1386 void getResultIDAndNumber(
OpResult result,
Value &lookupValue,
1387 std::optional<int> &lookupResultNo)
const;
1390 void setValueName(
Value value, StringRef name);
1394 StringRef uniqueValueName(StringRef name);
1417 llvm::ScopedHashTable<StringRef, char> usedNames;
1418 llvm::BumpPtrAllocator usedNameAllocator;
1421 unsigned nextValueID = 0;
1423 unsigned nextArgumentID = 0;
1425 unsigned nextConflictID = 0;
1434 : printerFlags(printerFlags) {
1435 llvm::SaveAndRestore valueIDSaver(nextValueID);
1436 llvm::SaveAndRestore argumentIDSaver(nextArgumentID);
1437 llvm::SaveAndRestore conflictIDSaver(nextConflictID);
1442 using UsedNamesScopeTy = llvm::ScopedHashTable<StringRef, char>::ScopeTy;
1443 using NamingContext =
1444 std::tuple<Region *, unsigned, unsigned, unsigned, UsedNamesScopeTy *>;
1447 llvm::BumpPtrAllocator allocator;
1450 auto *topLevelNamesScope =
1451 new (allocator.Allocate<UsedNamesScopeTy>()) UsedNamesScopeTy(usedNames);
1455 nameContext.push_back(std::make_tuple(®ion, nextValueID, nextArgumentID,
1456 nextConflictID, topLevelNamesScope));
1458 numberValuesInOp(*op);
1460 while (!nameContext.empty()) {
1462 UsedNamesScopeTy *parentScope;
1466 std::tie(region, std::ignore, std::ignore, std::ignore, parentScope) =
1467 nameContext.pop_back_val();
1469 std::tie(region, nextValueID, nextArgumentID, nextConflictID,
1470 parentScope) = nameContext.pop_back_val();
1474 while (usedNames.getCurScope() != parentScope) {
1475 usedNames.getCurScope()->~UsedNamesScopeTy();
1476 assert((usedNames.getCurScope() !=
nullptr || parentScope ==
nullptr) &&
1477 "top level parentScope must be a nullptr");
1481 auto *curNamesScope =
new (allocator.Allocate<UsedNamesScopeTy>())
1482 UsedNamesScopeTy(usedNames);
1484 numberValuesInRegion(*region);
1488 nameContext.push_back(std::make_tuple(®ion, nextValueID,
1489 nextArgumentID, nextConflictID,
1494 while (usedNames.getCurScope() !=
nullptr)
1495 usedNames.getCurScope()->~UsedNamesScopeTy();
1498 void SSANameState::printValueID(
Value value,
bool printResultNo,
1499 raw_ostream &stream)
const {
1501 stream <<
"<<NULL VALUE>>";
1505 std::optional<int> resultNo;
1506 auto lookupValue = value;
1510 if (
OpResult result = dyn_cast<OpResult>(value))
1511 getResultIDAndNumber(result, lookupValue, resultNo);
1513 auto it = valueIDs.find(lookupValue);
1514 if (it == valueIDs.end()) {
1515 stream <<
"<<UNKNOWN SSA VALUE>>";
1520 if (it->second != NameSentinel) {
1521 stream << it->second;
1523 auto nameIt = valueNames.find(lookupValue);
1524 assert(nameIt != valueNames.end() &&
"Didn't have a name entry?");
1525 stream << nameIt->second;
1528 if (resultNo && printResultNo)
1529 stream <<
'#' << *resultNo;
1532 void SSANameState::printOperationID(
Operation *op, raw_ostream &stream)
const {
1533 auto it = operationIDs.find(op);
1534 if (it == operationIDs.end()) {
1535 stream <<
"<<UNKNOWN OPERATION>>";
1537 stream <<
'%' << it->second;
1542 auto it = opResultGroups.find(op);
1543 return it == opResultGroups.end() ?
ArrayRef<int>() : it->second;
1546 BlockInfo SSANameState::getBlockInfo(
Block *block) {
1547 auto it = blockNames.find(block);
1548 BlockInfo invalidBlock{-1,
"INVALIDBLOCK"};
1549 return it != blockNames.end() ? it->second : invalidBlock;
1552 void SSANameState::shadowRegionArgs(
Region ®ion,
ValueRange namesToUse) {
1553 assert(!region.
empty() &&
"cannot shadow arguments of an empty region");
1555 "incorrect number of names passed in");
1557 "only KnownIsolatedFromAbove ops can shadow names");
1560 for (
unsigned i = 0, e = namesToUse.size(); i != e; ++i) {
1561 auto nameToUse = namesToUse[i];
1562 if (nameToUse ==
nullptr)
1567 llvm::raw_svector_ostream nameStream(nameStr);
1568 printValueID(nameToUse,
true, nameStream);
1571 assert(valueIDs[nameToReplace] == NameSentinel);
1574 auto name = StringRef(nameStream.str()).drop_front();
1577 valueNames[nameToReplace] = name.copy(usedNameAllocator);
1583 StringRef maybeGetValueNameFromLoc(
Value value, StringRef name) {
1585 return maybeNameLoc.getName();
1590 void SSANameState::numberValuesInRegion(
Region ®ion) {
1592 bool opAsmOpInterfaceUsed =
false;
1593 auto setBlockArgNameFn = [&](
Value arg, StringRef name) {
1594 assert(!valueIDs.count(arg) &&
"arg numbered multiple times");
1595 assert(llvm::cast<BlockArgument>(arg).getOwner()->getParent() == ®ion &&
1596 "arg not defined in current region");
1597 opAsmOpInterfaceUsed =
true;
1599 name = maybeGetValueNameFromLoc(arg, name);
1600 setValueName(arg, name);
1605 if (
auto asmInterface = dyn_cast<OpAsmOpInterface>(op))
1606 asmInterface.getAsmBlockArgumentNames(region, setBlockArgNameFn);
1608 if (!opAsmOpInterfaceUsed) {
1610 if (
auto interface = dyn_cast<OpAsmTypeInterface>(arg.
getType())) {
1611 interface.getAsmName(
1612 [&](StringRef name) { setBlockArgNameFn(arg, name); });
1620 unsigned nextBlockID = 0;
1621 for (
auto &block : region) {
1624 auto blockInfoIt = blockNames.insert({&block, {-1,
""}});
1625 if (blockInfoIt.second) {
1629 llvm::raw_string_ostream(name) <<
"^bb" << nextBlockID;
1630 blockInfoIt.first->second.name = StringRef(name).copy(usedNameAllocator);
1632 blockInfoIt.first->second.ordering = nextBlockID++;
1634 numberValuesInBlock(block);
1638 void SSANameState::numberValuesInBlock(
Block &block) {
1643 llvm::raw_svector_ostream specialName(specialNameBuffer);
1645 if (valueIDs.count(arg))
1648 specialNameBuffer.resize(strlen(
"arg"));
1649 specialName << nextArgumentID++;
1651 StringRef specialNameStr = specialName.str();
1653 specialNameStr = maybeGetValueNameFromLoc(arg, specialNameStr);
1654 setValueName(arg, specialNameStr);
1658 for (
auto &op : block)
1659 numberValuesInOp(op);
1662 void SSANameState::numberValuesInOp(
Operation &op) {
1666 bool opAsmOpInterfaceUsed =
false;
1667 auto setResultNameFn = [&](
Value result, StringRef name) {
1668 assert(!valueIDs.count(result) &&
"result numbered multiple times");
1669 assert(result.
getDefiningOp() == &op &&
"result not defined by 'op'");
1670 opAsmOpInterfaceUsed =
true;
1672 name = maybeGetValueNameFromLoc(result, name);
1673 setValueName(result, name);
1676 if (
int resultNo = llvm::cast<OpResult>(result).getResultNumber())
1677 resultGroups.push_back(resultNo);
1680 auto setBlockNameFn = [&](
Block *block, StringRef name) {
1682 "getAsmBlockArgumentNames callback invoked on a block not directly "
1683 "nested under the current operation");
1684 assert(!blockNames.count(block) &&
"block numbered multiple times");
1687 if (name.data() != tmpBuffer.data()) {
1688 tmpBuffer.append(name);
1689 name = tmpBuffer.str();
1691 name = name.copy(usedNameAllocator);
1692 blockNames[block] = {-1, name};
1696 if (OpAsmOpInterface asmInterface = dyn_cast<OpAsmOpInterface>(&op)) {
1697 asmInterface.getAsmBlockNames(setBlockNameFn);
1698 asmInterface.getAsmResultNames(setResultNameFn);
1700 if (!opAsmOpInterfaceUsed) {
1703 bool allHaveOpAsmTypeInterface =
1705 return isa<OpAsmTypeInterface>(type);
1707 if (allHaveOpAsmTypeInterface) {
1709 auto interface = cast<OpAsmTypeInterface>(result.
getType());
1710 interface.getAsmName(
1711 [&](StringRef name) { setResultNameFn(result, name); });
1718 if (numResults == 0) {
1721 if (operationIDs.try_emplace(&op, nextValueID).second)
1730 setValueName(resultBegin, nameLoc.getName());
1735 if (valueIDs.try_emplace(resultBegin, nextValueID).second)
1739 if (resultGroups.size() != 1) {
1740 llvm::array_pod_sort(resultGroups.begin(), resultGroups.end());
1741 opResultGroups.try_emplace(&op, std::move(resultGroups));
1745 void SSANameState::getResultIDAndNumber(
1747 std::optional<int> &lookupResultNo)
const {
1755 auto resultGroupIt = opResultGroups.find(owner);
1756 if (resultGroupIt == opResultGroups.end()) {
1758 lookupResultNo = resultNo;
1765 const auto *it = llvm::upper_bound(resultGroups, resultNo);
1766 int groupResultNo = 0, groupSize = 0;
1769 if (it == resultGroups.end()) {
1770 groupResultNo = resultGroups.back();
1771 groupSize =
static_cast<int>(owner->
getNumResults()) - resultGroups.back();
1774 groupResultNo = *std::prev(it);
1775 groupSize = *it - groupResultNo;
1780 lookupResultNo = resultNo - groupResultNo;
1781 lookupValue = owner->
getResult(groupResultNo);
1784 void SSANameState::setValueName(
Value value, StringRef name) {
1787 valueIDs[value] = nextValueID++;
1791 valueIDs[value] = NameSentinel;
1792 valueNames[value] = uniqueValueName(name);
1795 StringRef SSANameState::uniqueValueName(StringRef name) {
1800 if (!usedNames.count(name)) {
1801 name = name.copy(usedNameAllocator);
1807 probeName.push_back(
'_');
1809 probeName += llvm::utostr(nextConflictID++);
1810 if (!usedNames.count(probeName)) {
1811 name = probeName.str().copy(usedNameAllocator);
1814 probeName.resize(name.size() + 1);
1818 usedNames.insert(name,
char());
1828 class DistinctState {
1834 uint64_t distinctCounter = 0;
1839 uint64_t DistinctState::getId(
DistinctAttr distinctAttr) {
1840 auto [it, inserted] =
1841 distinctAttrMap.try_emplace(distinctAttr, distinctCounter);
1844 return it->getSecond();
1851 AsmParsedResourceEntry::~AsmParsedResourceEntry() =
default;
1852 AsmResourceBuilder::~AsmResourceBuilder() =
default;
1853 AsmResourceParser::~AsmResourceParser() =
default;
1854 AsmResourcePrinter::~AsmResourcePrinter() =
default;
1858 case AsmResourceEntryKind::Blob:
1860 case AsmResourceEntryKind::Bool:
1862 case AsmResourceEntryKind::String:
1865 llvm_unreachable(
"unknown AsmResourceEntryKind");
1869 std::unique_ptr<ResourceCollection> &collection = keyToResources[key.str()];
1871 collection = std::make_unique<ResourceCollection>(key);
1875 std::vector<std::unique_ptr<AsmResourcePrinter>>
1877 std::vector<std::unique_ptr<AsmResourcePrinter>> printers;
1878 for (
auto &it : keyToResources) {
1879 ResourceCollection *collection = it.second.get();
1881 return collection->buildResources(op, builder);
1883 printers.emplace_back(
1889 LogicalResult FallbackAsmResourceMap::ResourceCollection::parseResource(
1893 FailureOr<AsmResourceBlob> blob = entry.
parseAsBlob();
1896 resources.emplace_back(entry.
getKey(), std::move(*blob));
1903 resources.emplace_back(entry.
getKey(), *value);
1910 resources.emplace_back(entry.
getKey(), std::move(*str));
1917 void FallbackAsmResourceMap::ResourceCollection::buildResources(
1919 for (
const auto &entry : resources) {
1920 if (
const auto *value = std::get_if<AsmResourceBlob>(&entry.value))
1922 else if (
const auto *value = std::get_if<bool>(&entry.value))
1924 else if (
const auto *value = std::get_if<std::string>(&entry.value))
1927 llvm_unreachable(
"unknown AsmResourceEntryKind");
1941 : interfaces(op->
getContext()), nameState(op, printerFlags),
1942 printerFlags(printerFlags), locationMap(locationMap) {}
1945 : interfaces(ctx), printerFlags(printerFlags), locationMap(locationMap) {}
1949 aliasState.initialize(op, printerFlags, interfaces);
1969 return llvm::make_pointee_range(externalResourcePrinters);
1979 (*locationMap)[op] = std::make_pair(line, col);
1985 return dialectResources;
1989 return success(cyclicPrintingStack.insert(opaquePointer));
2005 AliasState aliasState;
2008 SSANameState nameState;
2011 DistinctState distinctState;
2027 template <
typename Range>
2031 [&stream](
const auto &dimSize) {
2032 if (ShapedType::isDynamic(dimSize))
2050 return printerFlags;
2054 auto parentThreadId = llvm::get_threadid();
2056 if (parentThreadId == llvm::get_threadid()) {
2058 diag.print(llvm::dbgs());
2059 llvm::dbgs() <<
"\n";
2065 if (failed(
verify(op))) {
2066 LLVM_DEBUG(llvm::dbgs()
2068 <<
"' failed to verify and will be printed in generic form\n");
2072 return printerFlags;
2091 return impl->getPrinterFlags();
2095 std::unique_ptr<AsmResourcePrinter> printer) {
2096 impl->externalResourcePrinters.emplace_back(std::move(printer));
2101 return impl->getDialectResources();
2109 : os(os), state(state), printerFlags(state.getPrinterFlags()) {}
2117 printLocation(loc, allowAlias);
2123 if (!isTopLevel && succeeded(state.getAliasState().getAlias(loc, os)))
2127 .Case<OpaqueLoc>([&](OpaqueLoc loc) {
2128 printLocationInternal(loc.getFallbackLocation(), pretty);
2130 .Case<UnknownLoc>([&](UnknownLoc loc) {
2138 os << loc.getFilename().getValue();
2140 printEscapedString(loc.getFilename());
2141 if (loc.getEndColumn() == loc.getStartColumn() &&
2142 loc.getStartLine() == loc.getEndLine()) {
2143 os <<
':' << loc.getStartLine() <<
':' << loc.getStartColumn();
2146 if (loc.getStartLine() == loc.getEndLine()) {
2147 os <<
':' << loc.getStartLine() <<
':' << loc.getStartColumn()
2148 <<
" to :" << loc.getEndColumn();
2151 os <<
':' << loc.getStartLine() <<
':' << loc.getStartColumn() <<
" to "
2152 << loc.getEndLine() <<
':' << loc.getEndColumn();
2154 .Case<NameLoc>([&](NameLoc loc) {
2155 printEscapedString(loc.getName());
2158 auto childLoc = loc.getChildLoc();
2159 if (!llvm::isa<UnknownLoc>(childLoc)) {
2161 printLocationInternal(childLoc, pretty);
2165 .Case<CallSiteLoc>([&](CallSiteLoc loc) {
2170 printLocationInternal(callee, pretty);
2172 if (llvm::isa<NameLoc>(callee)) {
2173 if (llvm::isa<FileLineColLoc>(caller)) {
2176 os << newLine <<
" at ";
2179 os << newLine <<
" at ";
2184 printLocationInternal(caller, pretty);
2188 .Case<FusedLoc>([&](
FusedLoc loc) {
2191 if (
Attribute metadata = loc.getMetadata()) {
2199 [&](Location loc) { printLocationInternal(loc, pretty); },
2200 [&]() { os << ", "; });
2203 .Default([&](LocationAttr loc) {
2204 // Assumes that this is a dialect-specific attribute and prints it
2206 printAttribute(loc);
2212 static void printFloatValue(const APFloat &apValue, raw_ostream &os,
2213 bool *printedHex = nullptr) {
2214 // We would like to output the FP constant value in exponential notation,
2215 // but we cannot do this if doing so will lose precision. Check here to
2216 // make sure that we only output it in exponential format if we can parse
2217 // the value back and get the same value.
2218 bool isInf = apValue.isInfinity();
2219 bool isNaN = apValue.isNaN();
2220 if (!isInf && !isNaN) {
2221 SmallString<128> strValue;
2222 apValue.toString(strValue, /*FormatPrecision=*/6, /*FormatMaxPadding=*/0,
2223 /*TruncateZero=*/false);
2225 // Check to make sure that the stringized number is not some string like
2226 // "Inf" or NaN, that atof will accept, but the lexer will not. Check
2227 // that the string matches the "[-+]?[0-9]" regex.
2228 assert(((strValue[0] >= '0
' && strValue[0] <= '9') ||
2229 ((strValue[0] ==
'-' || strValue[0] ==
'+') &&
2230 (strValue[1] >=
'0' && strValue[1] <=
'9'))) &&
2231 "[-+]?[0-9] regex does not match!");
2235 if (APFloat(apValue.getSemantics(), strValue).bitwiseIsEqual(apValue)) {
2243 apValue.toString(strValue);
2246 if (strValue.str().contains(
'.')) {
2257 APInt apInt = apValue.bitcastToAPInt();
2258 apInt.toString(str, 16,
false,
2265 return printLocationInternal(loc,
true,
true);
2269 printLocationInternal(loc,
false,
true);
2278 if (symName.empty() || !isalpha(symName.front()))
2283 symName = symName.drop_while(
2284 [](
char c) {
return llvm::isAlnum(c) || c ==
'.' || c ==
'_'; });
2285 if (symName.empty())
2290 return symName.front() ==
'<' && symName.back() ==
'>';
2295 StringRef dialectName, StringRef symString) {
2296 os << symPrefix << dialectName;
2301 os <<
'.' << symString;
2305 os << '<' << symString << '>
';
2309 static bool isBareIdentifier(StringRef name) {
2310 // By making this unsigned, the value passed in to isalnum will always be
2311 // in the range 0-255. This is important when building with MSVC because
2312 // its implementation will assert. This situation can arise when dealing
2313 // with UTF-8 multibyte characters.
2314 if (name.empty() || (!isalpha(name[0]) && name[0] != '_
'))
2316 return llvm::all_of(name.drop_front(), [](unsigned char c) {
2317 return isalnum(c) || c == '_
' || c == '$
' || c == '.
';
2323 static void printKeywordOrString(StringRef keyword, raw_ostream &os) {
2324 // If it can be represented as a bare identifier, write it directly.
2325 if (isBareIdentifier(keyword)) {
2330 // Otherwise, output the keyword wrapped in quotes with proper escaping.
2332 printEscapedString(keyword, os);
2339 static void printSymbolReference(StringRef symbolRef, raw_ostream &os) {
2340 if (symbolRef.empty()) {
2341 os << "@<<INVALID EMPTY SYMBOL>>
";
2345 printKeywordOrString(symbolRef, os);
2348 // Print out a valid ElementsAttr that is succinct and can represent any
2349 // potential shape/type, for use when eliding a large ElementsAttr.
2351 // We choose to use a dense resource ElementsAttr literal with conspicuous
2352 // content to hopefully alert readers to the fact that this has been elided.
2353 static void printElidedElementsAttr(raw_ostream &os) {
2354 os << R"(dense_resource<__elided__>)
";
2357 void AsmPrinter::Impl::printResourceHandle(
2358 const AsmDialectResourceHandle &resource) {
2359 auto *interface = cast<OpAsmDialectInterface>(resource.getDialect());
2360 ::printKeywordOrString(interface->getResourceKey(resource), os);
2361 state.getDialectResources()[resource.getDialect()].insert(resource);
2364 LogicalResult AsmPrinter::Impl::printAlias(Attribute attr) {
2365 return state.getAliasState().getAlias(attr, os);
2368 LogicalResult AsmPrinter::Impl::printAlias(Type type) {
2369 return state.getAliasState().getAlias(type, os);
2372 void AsmPrinter::Impl::printAttribute(Attribute attr,
2373 AttrTypeElision typeElision) {
2375 os << "<<NULL ATTRIBUTE>>
";
2379 // Try to print an alias for this attribute.
2380 if (succeeded(printAlias(attr)))
2382 return printAttributeImpl(attr, typeElision);
2385 void AsmPrinter::Impl::printAttributeImpl(Attribute attr,
2386 AttrTypeElision typeElision) {
2387 if (!isa<BuiltinDialect>(attr.getDialect())) {
2388 printDialectAttribute(attr);
2389 } else if (auto opaqueAttr = llvm::dyn_cast<OpaqueAttr>(attr)) {
2390 printDialectSymbol(os, "#
", opaqueAttr.getDialectNamespace(),
2391 opaqueAttr.getAttrData());
2392 } else if (llvm::isa<UnitAttr>(attr)) {
2395 } else if (auto distinctAttr = llvm::dyn_cast<DistinctAttr>(attr)) {
2396 os << "distinct[
" << state.getDistinctState().getId(distinctAttr) << "]<
";
2397 if (!llvm::isa<UnitAttr>(distinctAttr.getReferencedAttr())) {
2398 printAttribute(distinctAttr.getReferencedAttr());
2402 } else if (auto dictAttr = llvm::dyn_cast<DictionaryAttr>(attr)) {
2404 interleaveComma(dictAttr.getValue(),
2405 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2408 } else if (auto intAttr = llvm::dyn_cast<IntegerAttr>(attr)) {
2409 Type intType = intAttr.getType();
2410 if (intType.isSignlessInteger(1)) {
2411 os << (intAttr.getValue().getBoolValue() ? "true" : "false");
2413 // Boolean integer attributes always elides the type.
2417 // Only print attributes as unsigned if they are explicitly unsigned or are
2418 // signless 1-bit values. Indexes, signed values, and multi-bit signless
2419 // values print as signed.
2421 intType.isUnsignedInteger() || intType.isSignlessInteger(1);
2422 intAttr.getValue().print(os, !isUnsigned);
2424 // IntegerAttr elides the type if I64.
2425 if (typeElision == AttrTypeElision::May && intType.isSignlessInteger(64))
2428 } else if (auto floatAttr = llvm::dyn_cast<FloatAttr>(attr)) {
2429 bool printedHex = false;
2430 printFloatValue(floatAttr.getValue(), os, &printedHex);
2432 // FloatAttr elides the type if F64.
2433 if (typeElision == AttrTypeElision::May && floatAttr.getType().isF64() &&
2437 } else if (auto strAttr = llvm::dyn_cast<StringAttr>(attr)) {
2438 printEscapedString(strAttr.getValue());
2440 } else if (auto arrayAttr = llvm::dyn_cast<ArrayAttr>(attr)) {
2442 interleaveComma(arrayAttr.getValue(), [&](Attribute attr) {
2443 printAttribute(attr, AttrTypeElision::May);
2447 } else if (auto affineMapAttr = llvm::dyn_cast<AffineMapAttr>(attr)) {
2448 os << "affine_map<
";
2449 affineMapAttr.getValue().print(os);
2452 // AffineMap always elides the type.
2455 } else if (auto integerSetAttr = llvm::dyn_cast<IntegerSetAttr>(attr)) {
2456 os << "affine_set<
";
2457 integerSetAttr.getValue().print(os);
2460 // IntegerSet always elides the type.
2463 } else if (auto typeAttr = llvm::dyn_cast<TypeAttr>(attr)) {
2464 printType(typeAttr.getValue());
2466 } else if (auto refAttr = llvm::dyn_cast<SymbolRefAttr>(attr)) {
2467 printSymbolReference(refAttr.getRootReference().getValue(), os);
2468 for (FlatSymbolRefAttr nestedRef : refAttr.getNestedReferences()) {
2470 printSymbolReference(nestedRef.getValue(), os);
2473 } else if (auto intOrFpEltAttr =
2474 llvm::dyn_cast<DenseIntOrFPElementsAttr>(attr)) {
2475 if (printerFlags.shouldElideElementsAttr(intOrFpEltAttr)) {
2476 printElidedElementsAttr(os);
2479 printDenseIntOrFPElementsAttr(intOrFpEltAttr, /*allowHex=*/true);
2483 } else if (auto strEltAttr = llvm::dyn_cast<DenseStringElementsAttr>(attr)) {
2484 if (printerFlags.shouldElideElementsAttr(strEltAttr)) {
2485 printElidedElementsAttr(os);
2488 printDenseStringElementsAttr(strEltAttr);
2492 } else if (auto sparseEltAttr = llvm::dyn_cast<SparseElementsAttr>(attr)) {
2493 if (printerFlags.shouldElideElementsAttr(sparseEltAttr.getIndices()) ||
2494 printerFlags.shouldElideElementsAttr(sparseEltAttr.getValues())) {
2495 printElidedElementsAttr(os);
2498 DenseIntElementsAttr indices = sparseEltAttr.getIndices();
2499 if (indices.getNumElements() != 0) {
2500 printDenseIntOrFPElementsAttr(indices, /*allowHex=*/false);
2502 printDenseElementsAttr(sparseEltAttr.getValues(), /*allowHex=*/true);
2506 } else if (auto stridedLayoutAttr = llvm::dyn_cast<StridedLayoutAttr>(attr)) {
2507 stridedLayoutAttr.print(os);
2508 } else if (auto denseArrayAttr = llvm::dyn_cast<DenseArrayAttr>(attr)) {
2510 printType(denseArrayAttr.getElementType());
2511 if (!denseArrayAttr.empty()) {
2513 printDenseArrayAttr(denseArrayAttr);
2517 } else if (auto resourceAttr =
2518 llvm::dyn_cast<DenseResourceElementsAttr>(attr)) {
2519 os << "dense_resource<
";
2520 printResourceHandle(resourceAttr.getRawHandle());
2522 } else if (auto locAttr = llvm::dyn_cast<LocationAttr>(attr)) {
2523 printLocation(locAttr);
2525 llvm::report_fatal_error("Unknown builtin attribute
");
2527 // Don't print the type if we must elide it, or if it is a None type.
2528 if (typeElision != AttrTypeElision::Must) {
2529 if (auto typedAttr = llvm::dyn_cast<TypedAttr>(attr)) {
2530 Type attrType = typedAttr.getType();
2531 if (!llvm::isa<NoneType>(attrType)) {
2533 printType(attrType);
2540 static void printDenseIntElement(const APInt &value, raw_ostream &os,
2542 if (type.isInteger(1))
2543 os << (value.getBoolValue() ? "
true" : "false");
2545 value.print(os, !type.isUnsignedInteger());
2549 printDenseElementsAttrImpl(bool isSplat, ShapedType type, raw_ostream &os,
2550 function_ref<void(unsigned)> printEltFn) {
2551 // Special case for 0-d and splat tensors.
2553 return printEltFn(0);
2555 // Special case for degenerate tensors.
2556 auto numElements = type.getNumElements();
2557 if (numElements == 0)
2560 // We use a mixed-radix counter to iterate through the shape. When we bump a
2561 // non-least-significant digit, we emit a close bracket. When we next emit an
2562 // element we re-open all closed brackets.
2564 // The mixed-radix counter, with radices in 'shape'.
2565 int64_t rank = type.getRank();
2566 SmallVector<unsigned, 4> counter(rank, 0);
2567 // The number of brackets that have been opened and not closed.
2568 unsigned openBrackets = 0;
2570 auto shape = type.getShape();
2571 auto bumpCounter = [&] {
2572 // Bump the least significant digit.
2573 ++counter[rank - 1];
2574 // Iterate backwards bubbling back the increment.
2575 for (unsigned i = rank - 1; i > 0; --i)
2576 if (counter[i] >= shape[i]) {
2577 // Index 'i' is rolled over. Bump (i-1) and close a bracket.
2585 for (unsigned idx = 0, e = numElements; idx != e; ++idx) {
2588 while (openBrackets++ < rank)
2590 openBrackets = rank;
2594 while (openBrackets-- > 0)
2598 void AsmPrinter::Impl::printDenseElementsAttr(DenseElementsAttr attr,
2600 if (auto stringAttr = llvm::dyn_cast<DenseStringElementsAttr>(attr))
2601 return printDenseStringElementsAttr(stringAttr);
2603 printDenseIntOrFPElementsAttr(llvm::cast<DenseIntOrFPElementsAttr>(attr),
2607 void AsmPrinter::Impl::printDenseIntOrFPElementsAttr(
2608 DenseIntOrFPElementsAttr attr, bool allowHex) {
2609 auto type = attr.getType();
2610 auto elementType = type.getElementType();
2612 // Check to see if we should format this attribute as a hex string.
2613 if (allowHex && printerFlags.shouldPrintElementsAttrWithHex(attr)) {
2614 ArrayRef<char> rawData = attr.getRawData();
2615 if (llvm::endianness::native == llvm::endianness::big) {
2616 // Convert endianess in big-endian(BE) machines. `rawData` is BE in BE
2617 // machines. It is converted here to print in LE format.
2618 SmallVector<char, 64> outDataVec(rawData.size());
2619 MutableArrayRef<char> convRawData(outDataVec);
2620 DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
2621 rawData, convRawData, type);
2622 printHexString(convRawData);
2624 printHexString(rawData);
2630 if (ComplexType complexTy = llvm::dyn_cast<ComplexType>(elementType)) {
2631 Type complexElementType = complexTy.getElementType();
2632 // Note: The if and else below had a common lambda function which invoked
2633 // printDenseElementsAttrImpl. This lambda was hitting a bug in gcc 9.1,9.2
2634 // and hence was replaced.
2635 if (llvm::isa<IntegerType>(complexElementType)) {
2636 auto valueIt = attr.value_begin<std::complex<APInt>>();
2637 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2638 auto complexValue = *(valueIt + index);
2640 printDenseIntElement(complexValue.real(), os, complexElementType);
2642 printDenseIntElement(complexValue.imag(), os, complexElementType);
2646 auto valueIt = attr.value_begin<std::complex<APFloat>>();
2647 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2648 auto complexValue = *(valueIt + index);
2650 printFloatValue(complexValue.real(), os);
2652 printFloatValue(complexValue.imag(), os);
2656 } else if (elementType.isIntOrIndex()) {
2657 auto valueIt = attr.value_begin<APInt>();
2658 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2659 printDenseIntElement(*(valueIt + index), os, elementType);
2662 assert(llvm::isa<FloatType>(elementType) && "unexpected element type
");
2663 auto valueIt = attr.value_begin<APFloat>();
2664 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2665 printFloatValue(*(valueIt + index), os);
2670 void AsmPrinter::Impl::printDenseStringElementsAttr(
2671 DenseStringElementsAttr attr) {
2672 ArrayRef<StringRef> data = attr.getRawStringData();
2673 auto printFn = [&](unsigned index) { printEscapedString(data[index]); };
2674 printDenseElementsAttrImpl(attr.isSplat(), attr.getType(), os, printFn);
2677 void AsmPrinter::Impl::printDenseArrayAttr(DenseArrayAttr attr) {
2678 Type type = attr.getElementType();
2679 unsigned bitwidth = type.isInteger(1) ? 8 : type.getIntOrFloatBitWidth();
2680 unsigned byteSize = bitwidth / 8;
2681 ArrayRef<char> data = attr.getRawData();
2683 auto printElementAt = [&](unsigned i) {
2684 APInt value(bitwidth, 0);
2686 llvm::LoadIntFromMemory(
2687 value, reinterpret_cast<const uint8_t *>(data.begin() + byteSize * i),
2690 // Print the data as-is or as a float.
2691 if (type.isIntOrIndex()) {
2692 printDenseIntElement(value, getStream(), type);
2694 APFloat fltVal(llvm::cast<FloatType>(type).getFloatSemantics(), value);
2695 printFloatValue(fltVal, getStream());
2698 llvm::interleaveComma(llvm::seq<unsigned>(0, attr.size()), getStream(),
2702 void AsmPrinter::Impl::printType(Type type) {
2704 os << "<<NULL TYPE>>
";
2708 // Try to print an alias for this type.
2709 if (succeeded(printAlias(type)))
2711 return printTypeImpl(type);
2714 void AsmPrinter::Impl::printTypeImpl(Type type) {
2715 TypeSwitch<Type>(type)
2716 .Case<OpaqueType>([&](OpaqueType opaqueTy) {
2717 printDialectSymbol(os, "!
", opaqueTy.getDialectNamespace(),
2718 opaqueTy.getTypeData());
2720 .Case<IndexType>([&](Type) { os << "index
"; })
2721 .Case<Float4E2M1FNType>([&](Type) { os << "f4E2M1FN
"; })
2722 .Case<Float6E2M3FNType>([&](Type) { os << "f6E2M3FN
"; })
2723 .Case<Float6E3M2FNType>([&](Type) { os << "f6E3M2FN
"; })
2724 .Case<Float8E5M2Type>([&](Type) { os << "f8E5M2
"; })
2725 .Case<Float8E4M3Type>([&](Type) { os << "f8E4M3
"; })
2726 .Case<Float8E4M3FNType>([&](Type) { os << "f8E4M3FN
"; })
2727 .Case<Float8E5M2FNUZType>([&](Type) { os << "f8E5M2FNUZ
"; })
2728 .Case<Float8E4M3FNUZType>([&](Type) { os << "f8E4M3FNUZ
"; })
2729 .Case<Float8E4M3B11FNUZType>([&](Type) { os << "f8E4M3B11FNUZ
"; })
2730 .Case<Float8E3M4Type>([&](Type) { os << "f8E3M4
"; })
2731 .Case<Float8E8M0FNUType>([&](Type) { os << "f8E8M0FNU
"; })
2732 .Case<BFloat16Type>([&](Type) { os << "bf16"; })
2733 .Case<Float16Type>([&](Type) { os << "f16"; })
2734 .Case<FloatTF32Type>([&](Type) { os << "tf32
"; })
2735 .Case<Float32Type>([&](Type) { os << "f32
"; })
2736 .Case<Float64Type>([&](Type) { os << "f64
"; })
2737 .Case<Float80Type>([&](Type) { os << "f80
"; })
2738 .Case<Float128Type>([&](Type) { os << "f128
"; })
2739 .Case<IntegerType>([&](IntegerType integerTy) {
2740 if (integerTy.isSigned())
2742 else if (integerTy.isUnsigned())
2744 os << 'i' << integerTy.getWidth();
2746 .Case<FunctionType>([&](FunctionType funcTy) {
2748 interleaveComma(funcTy.getInputs(), [&](Type ty) { printType(ty); });
2750 ArrayRef<Type> results = funcTy.getResults();
2751 if (results.size() == 1 && !llvm::isa<FunctionType>(results[0])) {
2752 printType(results[0]);
2755 interleaveComma(results, [&](Type ty) { printType(ty); });
2759 .Case<VectorType>([&](VectorType vectorTy) {
2760 auto scalableDims = vectorTy.getScalableDims();
2762 auto vShape = vectorTy.getShape();
2763 unsigned lastDim = vShape.size();
2764 unsigned dimIdx = 0;
2765 for (dimIdx = 0; dimIdx < lastDim; dimIdx++) {
2766 if (!scalableDims.empty() && scalableDims[dimIdx])
2768 os << vShape[dimIdx];
2769 if (!scalableDims.empty() && scalableDims[dimIdx])
2773 printType(vectorTy.getElementType());
2776 .Case<RankedTensorType>([&](RankedTensorType tensorTy) {
2778 printDimensionList(tensorTy.getShape());
2779 if (!tensorTy.getShape().empty())
2781 printType(tensorTy.getElementType());
2782 // Only print the encoding attribute value if set.
2783 if (tensorTy.getEncoding()) {
2785 printAttribute(tensorTy.getEncoding());
2789 .Case<UnrankedTensorType>([&](UnrankedTensorType tensorTy) {
2791 printType(tensorTy.getElementType());
2794 .Case<MemRefType>([&](MemRefType memrefTy) {
2796 printDimensionList(memrefTy.getShape());
2797 if (!memrefTy.getShape().empty())
2799 printType(memrefTy.getElementType());
2800 MemRefLayoutAttrInterface layout = memrefTy.getLayout();
2801 if (!llvm::isa<AffineMapAttr>(layout) || !layout.isIdentity()) {
2803 printAttribute(memrefTy.getLayout(), AttrTypeElision::May);
2805 // Only print the memory space if it is the non-default one.
2806 if (memrefTy.getMemorySpace()) {
2808 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2812 .Case<UnrankedMemRefType>([&](UnrankedMemRefType memrefTy) {
2814 printType(memrefTy.getElementType());
2815 // Only print the memory space if it is the non-default one.
2816 if (memrefTy.getMemorySpace()) {
2818 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2822 .Case<ComplexType>([&](ComplexType complexTy) {
2824 printType(complexTy.getElementType());
2827 .Case<TupleType>([&](TupleType tupleTy) {
2829 interleaveComma(tupleTy.getTypes(),
2830 [&](Type type) { printType(type); });
2833 .Case<NoneType>([&](Type) { os << "none
"; })
2834 .Default([&](Type type) { return printDialectType(type); });
2837 void AsmPrinter::Impl::printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
2838 ArrayRef<StringRef> elidedAttrs,
2840 // If there are no attributes, then there is nothing to be done.
2844 // Functor used to print a filtered attribute list.
2845 auto printFilteredAttributesFn = [&](auto filteredAttrs) {
2846 // Print the 'attributes' keyword if necessary.
2848 os << " attributes
";
2850 // Otherwise, print them all out in braces.
2852 interleaveComma(filteredAttrs,
2853 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2857 // If no attributes are elided, we can directly print with no filtering.
2858 if (elidedAttrs.empty())
2859 return printFilteredAttributesFn(attrs);
2861 // Otherwise, filter out any attributes that shouldn't be included.
2862 llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
2864 auto filteredAttrs = llvm::make_filter_range(attrs, [&](NamedAttribute attr) {
2865 return !elidedAttrsSet.contains(attr.getName().strref());
2867 if (!filteredAttrs.empty())
2868 printFilteredAttributesFn(filteredAttrs);
2870 void AsmPrinter::Impl::printNamedAttribute(NamedAttribute attr) {
2871 // Print the name without quotes if possible.
2872 ::printKeywordOrString(attr.getName().strref(), os);
2874 // Pretty printing elides the attribute value for unit attributes.
2875 if (llvm::isa<UnitAttr>(attr.getValue()))
2879 printAttribute(attr.getValue());
2882 void AsmPrinter::Impl::printDialectAttribute(Attribute attr) {
2883 auto &dialect = attr.getDialect();
2885 // Ask the dialect to serialize the attribute to a string.
2886 std::string attrName;
2888 llvm::raw_string_ostream attrNameStr(attrName);
2889 Impl subPrinter(attrNameStr, state);
2890 DialectAsmPrinter printer(subPrinter);
2891 dialect.printAttribute(attr, printer);
2893 printDialectSymbol(os, "#
", dialect.getNamespace(), attrName);
2896 void AsmPrinter::Impl::printDialectType(Type type) {
2897 auto &dialect = type.getDialect();
2899 // Ask the dialect to serialize the type to a string.
2900 std::string typeName;
2902 llvm::raw_string_ostream typeNameStr(typeName);
2903 Impl subPrinter(typeNameStr, state);
2904 DialectAsmPrinter printer(subPrinter);
2905 dialect.printType(type, printer);
2907 printDialectSymbol(os, "!
", dialect.getNamespace(), typeName);
2910 void AsmPrinter::Impl::printEscapedString(StringRef str) {
2912 llvm::printEscapedString(str, os);
2917 os <<
"\"0x" << llvm::toHex(str) <<
"\"";
2920 printHexString(StringRef(data.data(), data.size()));
2924 return state.pushCyclicPrinting(opaquePointer);
2940 assert(
impl &&
"expected AsmPrinter::getStream to be overriden");
2941 return impl->getStream();
2946 assert(
impl &&
"expected AsmPrinter::printFloat to be overriden");
2951 assert(
impl &&
"expected AsmPrinter::printType to be overriden");
2952 impl->printType(type);
2956 assert(
impl &&
"expected AsmPrinter::printAttribute to be overriden");
2957 impl->printAttribute(attr);
2961 assert(
impl &&
"expected AsmPrinter::printAlias to be overriden");
2962 return impl->printAlias(attr);
2966 assert(
impl &&
"expected AsmPrinter::printAlias to be overriden");
2967 return impl->printAlias(type);
2972 "expected AsmPrinter::printAttributeWithoutType to be overriden");
2977 assert(
impl &&
"expected AsmPrinter::printKeywordOrString to be overriden");
2982 assert(
impl &&
"expected AsmPrinter::printString to be overriden");
2984 printEscapedString(keyword,
getStream());
2989 assert(
impl &&
"expected AsmPrinter::printSymbolName to be overriden");
2994 assert(
impl &&
"expected AsmPrinter::printResourceHandle to be overriden");
2995 impl->printResourceHandle(resource);
3003 return impl->pushCyclicPrinting(opaquePointer);
3014 printAffineExprInternal(expr, BindingStrength::Weak, printValueName);
3020 const char *binopSpelling =
nullptr;
3023 unsigned pos = cast<AffineSymbolExpr>(expr).getPosition();
3025 printValueName(pos,
true);
3031 unsigned pos = cast<AffineDimExpr>(expr).getPosition();
3033 printValueName(pos,
false);
3039 os << cast<AffineConstantExpr>(expr).getValue();
3042 binopSpelling =
" + ";
3045 binopSpelling =
" * ";
3048 binopSpelling =
" floordiv ";
3051 binopSpelling =
" ceildiv ";
3054 binopSpelling =
" mod ";
3058 auto binOp = cast<AffineBinaryOpExpr>(expr);
3064 if (enclosingTightness == BindingStrength::Strong)
3068 auto rhsConst = dyn_cast<AffineConstantExpr>(rhsExpr);
3070 rhsConst.getValue() == -1) {
3072 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
3073 if (enclosingTightness == BindingStrength::Strong)
3078 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
3080 os << binopSpelling;
3081 printAffineExprInternal(rhsExpr, BindingStrength::Strong, printValueName);
3083 if (enclosingTightness == BindingStrength::Strong)
3089 if (enclosingTightness == BindingStrength::Strong)
3094 if (
auto rhs = dyn_cast<AffineBinaryOpExpr>(rhsExpr)) {
3097 if (
auto rrhs = dyn_cast<AffineConstantExpr>(rrhsExpr)) {
3098 if (rrhs.getValue() == -1) {
3099 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
3103 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
3106 printAffineExprInternal(rhs.getLHS(), BindingStrength::Weak,
3110 if (enclosingTightness == BindingStrength::Strong)
3115 if (rrhs.getValue() < -1) {
3116 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
3119 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
3121 os <<
" * " << -rrhs.getValue();
3122 if (enclosingTightness == BindingStrength::Strong)
3131 if (
auto rhsConst = dyn_cast<AffineConstantExpr>(rhsExpr)) {
3132 if (rhsConst.getValue() < 0) {
3133 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
3134 os <<
" - " << -rhsConst.getValue();
3135 if (enclosingTightness == BindingStrength::Strong)
3141 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
3144 printAffineExprInternal(rhsExpr, BindingStrength::Weak, printValueName);
3146 if (enclosingTightness == BindingStrength::Strong)
3151 printAffineExprInternal(expr, BindingStrength::Weak);
3152 isEq ? os <<
" == 0" : os <<
" >= 0";
3158 for (
int i = 0; i < (int)map.
getNumDims() - 1; ++i)
3159 os <<
'd' << i <<
", ";
3168 os <<
's' << i <<
", ";
3177 [&](
AffineExpr expr) { printAffineExpr(expr); });
3184 for (
unsigned i = 1; i < set.
getNumDims(); ++i)
3185 os <<
'd' << i - 1 <<
", ";
3194 os <<
's' << i <<
", ";
3203 for (
int i = 1; i < numConstraints; ++i) {
3207 if (numConstraints >= 1)
3208 printAffineConstraint(set.
getConstraint(numConstraints - 1),
3209 set.
isEq(numConstraints - 1));
3224 explicit OperationPrinter(raw_ostream &os,
AsmStateImpl &state)
3228 void printTopLevelOperation(
Operation *op);
3232 void printFullOpWithIndentAndLoc(
Operation *op);
3238 void printCustomOrGenericOp(
Operation *op)
override;
3240 void printGenericOp(
Operation *op,
bool printOpName)
override;
3243 void printBlockName(
Block *block);
3248 void print(
Block *block,
bool printBlockArgs =
true,
3249 bool printBlockTerminator =
true);
3252 void printValueID(
Value value,
bool printResultNo =
true,
3253 raw_ostream *streamOverride =
nullptr)
const;
3257 raw_ostream *streamOverride =
nullptr)
const;
3265 void printOptionalLocationSpecifier(
Location loc)
override {
3266 printTrailingLocation(loc);
3273 os.indent(currentIndent);
3277 void increaseIndent()
override { currentIndent += indentWidth; }
3280 void decreaseIndent()
override { currentIndent -= indentWidth; }
3289 bool omitType =
false)
override;
3292 void printOperand(
Value value)
override { printValueID(value); }
3293 void printOperand(
Value value, raw_ostream &os)
override {
3294 printValueID(value,
true, &os);
3302 void printOptionalAttrDictWithKeyword(
3310 void printSuccessor(
Block *successor)
override;
3314 void printSuccessorAndUseList(
Block *successor,
3319 bool printBlockTerminators,
bool printEmptyBlock)
override;
3326 state.getSSANameState().shadowRegionArgs(region, namesToUse);
3331 void printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3346 void printValueUsers(
Value value);
3350 void printUserIDs(
Operation *user,
bool prefixComma =
false);
3358 using PrintFn =
function_ref<void(StringRef, ValueFn)>;
3360 ResourceBuilder(PrintFn printFn) : printFn(printFn) {}
3361 ~ResourceBuilder()
override =
default;
3363 void buildBool(StringRef key,
bool data)
final {
3364 printFn(key, [&](raw_ostream &os) { os << (data ?
"true" :
"false"); });
3367 void buildString(StringRef key, StringRef data)
final {
3368 printFn(key, [&](raw_ostream &os) {
3370 llvm::printEscapedString(data, os);
3376 uint32_t dataAlignment)
final {
3377 printFn(key, [&](raw_ostream &os) {
3379 llvm::support::ulittle32_t dataAlignmentLE(dataAlignment);
3381 << llvm::toHex(StringRef(
reinterpret_cast<char *
>(&dataAlignmentLE),
3382 sizeof(dataAlignment)))
3383 << llvm::toHex(StringRef(data.data(), data.size())) <<
"\"";
3392 void printFileMetadataDictionary(
Operation *op);
3398 void printResourceFileMetadata(
function_ref<
void()> checkAddMetadataDict,
3409 const static unsigned indentWidth = 2;
3412 unsigned currentIndent = 0;
3416 void OperationPrinter::printTopLevelOperation(
Operation *op) {
3418 state.getAliasState().printNonDeferredAliases(*
this, newLine);
3421 printFullOpWithIndentAndLoc(op);
3425 state.getAliasState().printDeferredAliases(*
this, newLine);
3428 printFileMetadataDictionary(op);
3431 void OperationPrinter::printFileMetadataDictionary(
Operation *op) {
3432 bool sawMetadataEntry =
false;
3433 auto checkAddMetadataDict = [&] {
3434 if (!std::exchange(sawMetadataEntry,
true))
3435 os << newLine <<
"{-#" << newLine;
3439 printResourceFileMetadata(checkAddMetadataDict, op);
3442 if (sawMetadataEntry)
3443 os << newLine <<
"#-}" << newLine;
3446 void OperationPrinter::printResourceFileMetadata(
3449 bool hadResource =
false;
3450 bool needResourceComma =
false;
3451 bool needEntryComma =
false;
3452 auto processProvider = [&](StringRef dictName, StringRef name,
auto &provider,
3453 auto &&...providerArgs) {
3454 bool hadEntry =
false;
3455 auto printFn = [&](StringRef key, ResourceBuilder::ValueFn valueFn) {
3456 checkAddMetadataDict();
3458 std::string resourceStr;
3459 auto printResourceStr = [&](raw_ostream &os) { os << resourceStr; };
3460 std::optional<uint64_t> charLimit =
3462 if (charLimit.has_value()) {
3464 if (charLimit.value() == 0)
3467 llvm::raw_string_ostream ss(resourceStr);
3471 if (resourceStr.size() > charLimit.value())
3475 valueFn = printResourceStr;
3479 if (!std::exchange(hadResource,
true)) {
3480 if (needResourceComma)
3481 os <<
"," << newLine;
3482 os <<
" " << dictName <<
"_resources: {" << newLine;
3485 if (!std::exchange(hadEntry,
true)) {
3487 os <<
"," << newLine;
3488 os <<
" " << name <<
": {" << newLine;
3490 os <<
"," << newLine;
3498 ResourceBuilder entryBuilder(printFn);
3499 provider.buildResources(op, providerArgs..., entryBuilder);
3501 needEntryComma |= hadEntry;
3503 os << newLine <<
" }";
3509 auto &dialectResources = state.getDialectResources();
3510 StringRef name = interface.getDialect()->getNamespace();
3511 auto it = dialectResources.find(interface.getDialect());
3512 if (it != dialectResources.end())
3513 processProvider(
"dialect", name, interface, it->second);
3515 processProvider(
"dialect", name, interface,
3519 os << newLine <<
" }";
3523 needEntryComma =
false;
3524 needResourceComma = hadResource;
3525 hadResource =
false;
3526 for (
const auto &printer : state.getResourcePrinters())
3527 processProvider(
"external", printer.getName(), printer);
3529 os << newLine <<
" }";
3537 void OperationPrinter::printRegionArgument(
BlockArgument arg,
3545 printOptionalAttrDict(argAttrs);
3547 printTrailingLocation(arg.
getLoc(),
false);
3550 void OperationPrinter::printFullOpWithIndentAndLoc(
Operation *op) {
3552 state.registerOperationLocation(op, newLine.curLine, currentIndent);
3554 os.indent(currentIndent);
3556 printTrailingLocation(op->
getLoc());
3558 printUsersComment(op);
3561 void OperationPrinter::printFullOp(
Operation *op) {
3563 auto printResultGroup = [&](
size_t resultNo,
size_t resultCount) {
3564 printValueID(op->
getResult(resultNo),
false);
3565 if (resultCount > 1)
3566 os <<
':' << resultCount;
3570 ArrayRef<int> resultGroups = state.getSSANameState().getOpResultGroups(op);
3571 if (!resultGroups.empty()) {
3574 interleaveComma(llvm::seq<int>(0, resultGroups.size() - 1), [&](
int i) {
3575 printResultGroup(resultGroups[i],
3576 resultGroups[i + 1] - resultGroups[i]);
3579 printResultGroup(resultGroups.back(), numResults - resultGroups.back());
3582 printResultGroup(0, numResults);
3588 printCustomOrGenericOp(op);
3591 void OperationPrinter::printUsersComment(
Operation *op) {
3595 printOperationID(op);
3596 }
else if (numResults && op->
use_empty()) {
3598 }
else if (numResults && !op->
use_empty()) {
3601 unsigned usedInNResults = 0;
3602 unsigned usedInNOperations = 0;
3605 if (userSet.insert(user).second) {
3606 ++usedInNOperations;
3607 usedInNResults += user->getNumResults();
3612 bool exactlyOneUniqueUse =
3613 usedInNResults <= 1 && usedInNOperations <= 1 && numResults == 1;
3614 os <<
" // " << (exactlyOneUniqueUse ?
"user" :
"users") <<
": ";
3615 bool shouldPrintBrackets = numResults > 1;
3616 auto printOpResult = [&](
OpResult opResult) {
3617 if (shouldPrintBrackets)
3619 printValueUsers(opResult);
3620 if (shouldPrintBrackets)
3624 interleaveComma(op->
getResults(), printOpResult);
3628 void OperationPrinter::printUsersComment(
BlockArgument arg) {
3634 os <<
" is used by ";
3635 printValueUsers(arg);
3640 void OperationPrinter::printValueUsers(
Value value) {
3648 if (userSet.insert(user).second)
3649 printUserIDs(user, index);
3653 void OperationPrinter::printUserIDs(
Operation *user,
bool prefixComma) {
3658 printOperationID(user);
3661 [
this](
Value result) { printValueID(result); });
3665 void OperationPrinter::printCustomOrGenericOp(
Operation *op) {
3671 opInfo->printAssembly(op, *
this, defaultDialectStack.back());
3676 if (
auto opPrinter = dialect->getOperationPrinter(op)) {
3681 if (name.count(
'.') == 1)
3682 name.consume_front((defaultDialectStack.back() +
".").str());
3686 opPrinter(op, *
this);
3693 printGenericOp(op,
true);
3696 void OperationPrinter::printGenericOp(
Operation *op,
bool printOpName) {
3700 interleaveComma(op->
getOperands(), [&](
Value value) { printValueID(value); });
3707 [&](
Block *successor) { printBlockName(successor); });
3719 if (op->getNumRegions() != 0) {
3721 interleaveComma(op->getRegions(), [&](Region ®ion) {
3722 printRegion(region, /*printEntryBlockArgs=*/true,
3723 /*printBlockTerminators=*/true, /*printEmptyBlock=*/true);
3728 printOptionalAttrDict(op->getPropertiesStorage()
3729 ? llvm::to_vector(op->getDiscardableAttrs())
3732 // Print the type signature of the operation.
3734 printFunctionalType(op);
3737 void OperationPrinter::printBlockName(Block *block) {
3738 os << state.getSSANameState().getBlockInfo(block).name;
3741 void OperationPrinter::print(Block *block, bool printBlockArgs,
3742 bool printBlockTerminator) {
3743 // Print the block label and argument list if requested.
3744 if (printBlockArgs) {
3745 os.indent(currentIndent);
3746 printBlockName(block);
3748 // Print the argument list if non-empty.
3749 if (!block->args_empty()) {
3751 interleaveComma(block->getArguments(), [&](BlockArgument arg) {
3754 printType(arg.getType());
3755 // TODO: We should allow location aliases on block arguments.
3756 printTrailingLocation(arg.getLoc(), /*allowAlias*/ false);
3762 // Print out some context information about the predecessors of this block.
3763 if (!block->getParent()) {
3764 os << " // block is not in a region!";
3765 } else if (block->hasNoPredecessors()) {
3766 if (!block->isEntryBlock())
3767 os << " // no predecessors";
3768 } else if (auto *pred = block->getSinglePredecessor()) {
3770 printBlockName(pred);
3772 // We want to print the predecessors in a stable order, not in
3773 // whatever order the use-list is in, so gather and sort them.
3774 SmallVector<BlockInfo, 4> predIDs;
3775 for (auto *pred : block->getPredecessors())
3776 predIDs.push_back(state.getSSANameState().getBlockInfo(pred));
3777 llvm::sort(predIDs, [](BlockInfo lhs, BlockInfo rhs) {
3778 return lhs.ordering < rhs.ordering;
3781 os << " // " << predIDs.size() << " preds: ";
3783 interleaveComma(predIDs, [&](BlockInfo pred) { os << pred.name; });
3788 currentIndent += indentWidth;
3790 if (printerFlags.shouldPrintValueUsers()) {
3791 for (BlockArgument arg : block->getArguments()) {
3792 os.indent(currentIndent);
3793 printUsersComment(arg);
3797 bool hasTerminator =
3798 !block->empty() && block->back().hasTrait<OpTrait::IsTerminator>();
3799 auto range = llvm::make_range(
3801 std::prev(block->end(),
3802 (!hasTerminator || printBlockTerminator) ? 0 : 1));
3803 for (auto &op : range) {
3804 printFullOpWithIndentAndLoc(&op);
3807 currentIndent -= indentWidth;
3810 void OperationPrinter::printValueID(Value value, bool printResultNo,
3811 raw_ostream *streamOverride) const {
3812 state.getSSANameState().printValueID(value, printResultNo,
3813 streamOverride ? *streamOverride : os);
3816 void OperationPrinter::printOperationID(Operation *op,
3817 raw_ostream *streamOverride) const {
3818 state.getSSANameState().printOperationID(op, streamOverride ? *streamOverride
3822 void OperationPrinter::printSuccessor(Block *successor) {
3823 printBlockName(successor);
3826 void OperationPrinter::printSuccessorAndUseList(Block *successor,
3827 ValueRange succOperands) {
3828 printBlockName(successor);
3829 if (succOperands.empty())
3833 interleaveComma(succOperands,
3834 [this](Value operand) { printValueID(operand); });
3836 interleaveComma(succOperands,
3837 [this](Value operand) { printType(operand.getType()); });
3841 void OperationPrinter::printRegion(Region ®ion, bool printEntryBlockArgs,
3842 bool printBlockTerminators,
3843 bool printEmptyBlock) {
3844 if (printerFlags.shouldSkipRegions()) {
3848 os << "{" << newLine;
3849 if (!region.empty()) {
3850 auto restoreDefaultDialect =
3851 llvm::make_scope_exit([&]() { defaultDialectStack.pop_back(); });
3852 if (auto iface = dyn_cast<OpAsmOpInterface>(region.getParentOp()))
3853 defaultDialectStack.push_back(iface.getDefaultDialect());
3855 defaultDialectStack.push_back("");
3857 auto *entryBlock = ®ion.front();
3858 // Force printing the block header if printEmptyBlock is set and the block
3859 // is empty or if printEntryBlockArgs is set and there are arguments to
3861 bool shouldAlwaysPrintBlockHeader =
3862 (printEmptyBlock && entryBlock->empty()) ||
3863 (printEntryBlockArgs && entryBlock->getNumArguments() != 0);
3864 print(entryBlock, shouldAlwaysPrintBlockHeader, printBlockTerminators);
3865 for (auto &b : llvm::drop_begin(region.getBlocks(), 1))
3868 os.indent(currentIndent) << "}";
3871 void OperationPrinter::printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3872 ValueRange operands) {
3874 os << "<<NULL AFFINE MAP>>";
3877 AffineMap map = mapAttr.getValue();
3878 unsigned numDims = map.getNumDims();
3879 auto printValueName = [&](unsigned pos, bool isSymbol) {
3880 unsigned index = isSymbol ? numDims + pos : pos;
3881 assert(index < operands.size());
3884 printValueID(operands[index]);
3889 interleaveComma(map.getResults(), [&](AffineExpr expr) {
3890 printAffineExpr(expr, printValueName);
3894 void OperationPrinter::printAffineExprOfSSAIds(AffineExpr expr,
3895 ValueRange dimOperands,
3896 ValueRange symOperands) {
3897 auto printValueName = [&](unsigned pos, bool isSymbol) {
3899 return printValueID(dimOperands[pos]);
3901 printValueID(symOperands[pos]);
3904 printAffineExpr(expr, printValueName);
3907 //===----------------------------------------------------------------------===//
3908 // print and dump methods
3909 //===----------------------------------------------------------------------===//
3911 void Attribute::print(raw_ostream &os, bool elideType) const {
3913 os << "<<NULL ATTRIBUTE>>";
3917 AsmState state(getContext());
3918 print(os, state, elideType);
3920 void Attribute::print(raw_ostream &os, AsmState &state, bool elideType) const {
3921 using AttrTypeElision = AsmPrinter::Impl::AttrTypeElision;
3922 AsmPrinter::Impl(os, state.getImpl())
3923 .printAttribute(*this, elideType ? AttrTypeElision::Must
3924 : AttrTypeElision::Never);
3927 void Attribute::dump() const {
3928 print(llvm::errs());
3929 llvm::errs() << "\n";
3932 void Attribute::printStripped(raw_ostream &os, AsmState &state) const {
3934 os << "<<NULL ATTRIBUTE>>";
3938 AsmPrinter::Impl subPrinter(os, state.getImpl());
3939 if (succeeded(subPrinter.printAlias(*this)))
3942 auto &dialect = this->getDialect();
3943 uint64_t posPrior = os.tell();
3944 DialectAsmPrinter printer(subPrinter);
3945 dialect.printAttribute(*this, printer);
3946 if (posPrior != os.tell())
3949 // Fallback to printing with prefix if the above failed to write anything
3950 // to the output stream.
3953 void Attribute::printStripped(raw_ostream &os) const {
3955 os << "<<NULL ATTRIBUTE>>";
3959 AsmState state(getContext());
3960 printStripped(os, state);
3963 void Type::print(raw_ostream &os) const {
3965 os << "<<NULL TYPE>>";
3969 AsmState state(getContext());
3972 void Type::print(raw_ostream &os, AsmState &state) const {
3973 AsmPrinter::Impl(os, state.getImpl()).printType(*this);
3976 void Type::dump() const {
3977 print(llvm::errs());
3978 llvm::errs() << "\n";
3981 void AffineMap::dump() const {
3982 print(llvm::errs());
3983 llvm::errs() << "\n";
3986 void IntegerSet::dump() const {
3987 print(llvm::errs());
3988 llvm::errs() << "\n";
3991 void AffineExpr::print(raw_ostream &os) const {
3993 os << "<<NULL AFFINE EXPR>>";
3996 AsmState state(getContext());
3997 AsmPrinter::Impl(os, state.getImpl()).printAffineExpr(*this);
4000 void AffineExpr::dump() const {
4001 print(llvm::errs());
4002 llvm::errs() << "\n";
4005 void AffineMap::print(raw_ostream &os) const {
4007 os << "<<NULL AFFINE MAP>>";
4010 AsmState state(getContext());
4011 AsmPrinter::Impl(os, state.getImpl()).printAffineMap(*this);
4014 void IntegerSet::print(raw_ostream &os) const {
4015 AsmState state(getContext());
4016 AsmPrinter::Impl(os, state.getImpl()).printIntegerSet(*this);
4019 void Value::print(raw_ostream &os) const { print(os, OpPrintingFlags()); }
4020 void Value::print(raw_ostream &os, const OpPrintingFlags &flags) const {
4022 os << "<<NULL VALUE>>";
4026 if (auto *op = getDefiningOp())
4027 return op->print(os, flags);
4028 // TODO: Improve BlockArgument print'ing.
4030 os <<
"<block argument> of type '" << arg.
getType()
4035 os <<
"<<NULL VALUE>>";
4039 if (
auto *op = getDefiningOp())
4040 return op->
print(os, state);
4044 os <<
"<block argument> of type '" << arg.
getType()
4049 print(llvm::errs());
4050 llvm::errs() <<
"\n";
4058 state.getImpl().getSSANameState().printValueID(*
this,
true,
4081 if (
auto result = llvm::dyn_cast<OpResult>(*
this)) {
4084 op = llvm::cast<BlockArgument>(*this).getOwner()->
getParentOp();
4086 os <<
"<<UNKNOWN SSA VALUE>>";
4092 printAsOperand(os, state);
4102 OperationPrinter printer(os, state.getImpl());
4103 if (!getParent() && !state.getPrinterFlags().shouldUseLocalScope()) {
4104 state.getImpl().initializeAliases(
this);
4105 printer.printTopLevelOperation(
this);
4107 printer.printFullOpWithIndentAndLoc(
this);
4113 llvm::errs() <<
"\n";
4118 llvm::errs() <<
"\n";
4124 os <<
"<<UNLINKED BLOCK>>\n";
4135 OperationPrinter(os, state.getImpl()).print(
this);
4144 os <<
"<<UNLINKED BLOCK>>\n";
4148 printAsOperand(os, state);
4151 OperationPrinter printer(os, state.getImpl());
4152 printer.printBlockName(
this);
4167 if (dimensions.empty())
4170 if (dimensions.empty())
4180 <<
"Failed parsing dimension list.";
4191 <<
"Failed parsing dimension list.";
4193 if (shapeArr.empty()) {
4195 <<
"Failed parsing dimension list. Did you mean an empty list? It "
4196 "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::@1204::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.