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, [](
const auto &lhs,
const auto &rhs) {
1114 return lhs.second < rhs.second;
1119 llvm::BumpPtrAllocator usedAliasAllocator;
1122 llvm::StringMap<unsigned> nameCounts;
1123 for (
auto &[symbol, aliasInfo] : unprocessedAliases) {
1124 if (!aliasInfo.alias)
1126 StringRef alias = *aliasInfo.alias;
1127 unsigned nameIndex = uniqueAliasNameIndex(alias, nameCounts, usedAliases);
1128 symbolToAlias.insert(
1129 {symbol, SymbolAlias(alias, nameIndex, aliasInfo.isType,
1130 aliasInfo.canBeDeferred)});
1134 void AliasInitializer::initialize(
1136 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias) {
1140 DummyAliasOperationPrinter aliasPrinter(printerFlags, *
this);
1141 aliasPrinter.printCustomOrGenericOp(op);
1144 initializeAliases(aliases, attrTypeToAlias);
1147 template <
typename T,
typename... PrintArgs>
1148 std::pair<size_t, size_t> AliasInitializer::visitImpl(
1149 T value, llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
1150 bool canBeDeferred, PrintArgs &&...printArgs) {
1151 auto [it, inserted] =
1152 aliases.insert({value.getAsOpaquePointer(), InProgressAliasInfo()});
1153 size_t aliasIndex = std::distance(aliases.begin(), it);
1157 markAliasNonDeferrable(aliasIndex);
1158 return {
static_cast<size_t>(it->second.aliasDepth), aliasIndex};
1162 generateAlias(value, it->second, canBeDeferred);
1163 it->second.isType = std::is_base_of_v<Type, T>;
1164 it->second.canBeDeferred = canBeDeferred;
1168 DummyAliasDialectAsmPrinter printer(*
this, canBeDeferred, childAliases);
1169 size_t maxAliasDepth =
1170 printer.printAndVisitNestedAliases(value, printArgs...);
1173 it = std::next(aliases.begin(), aliasIndex);
1176 it->second.childIndices = std::move(childAliases);
1178 it->second.aliasDepth = maxAliasDepth + 1;
1181 return {(size_t)it->second.aliasDepth, aliasIndex};
1184 void AliasInitializer::markAliasNonDeferrable(
size_t aliasIndex) {
1185 auto *it = std::next(aliases.begin(), aliasIndex);
1189 if (!it->second.canBeDeferred)
1192 it->second.canBeDeferred =
false;
1195 for (
size_t childIndex : it->second.childIndices)
1196 markAliasNonDeferrable(childIndex);
1199 template <
typename T>
1200 void AliasInitializer::generateAlias(T symbol, InProgressAliasInfo &alias,
1201 bool canBeDeferred) {
1206 using InterfaceT = std::conditional_t<std::is_base_of_v<Attribute, T>,
1207 OpAsmAttrInterface, OpAsmTypeInterface>;
1208 if (
auto symbolInterface = dyn_cast<InterfaceT>(symbol)) {
1209 symbolInterfaceResult = symbolInterface.getAlias(aliasOS);
1211 nameBuffer = std::move(aliasBuffer);
1212 assert(!nameBuffer.empty() &&
"expected valid alias name");
1216 if (symbolInterfaceResult != OpAsmDialectInterface::AliasResult::FinalAlias) {
1217 for (
const auto &interface : interfaces) {
1219 interface.getAlias(symbol, aliasOS);
1222 nameBuffer = std::move(aliasBuffer);
1223 assert(!nameBuffer.empty() &&
"expected valid alias name");
1224 if (result == OpAsmDialectInterface::AliasResult::FinalAlias)
1229 if (nameBuffer.empty())
1235 name = name.copy(aliasAllocator);
1236 alias = InProgressAliasInfo(name);
1254 LogicalResult getAlias(
Attribute attr, raw_ostream &os)
const;
1258 LogicalResult getAlias(
Type ty, raw_ostream &os)
const;
1262 void printNonDeferredAliases(
AsmPrinter::Impl &p, NewLineCounter &newLine) {
1263 printAliases(p, newLine,
false);
1268 printAliases(p, newLine,
true);
1278 llvm::MapVector<const void *, SymbolAlias> attrTypeToAlias;
1281 llvm::BumpPtrAllocator aliasAllocator;
1285 void AliasState::initialize(
1288 AliasInitializer initializer(interfaces, aliasAllocator);
1289 initializer.initialize(op, printerFlags, attrTypeToAlias);
1292 LogicalResult AliasState::getAlias(
Attribute attr, raw_ostream &os)
const {
1294 if (it == attrTypeToAlias.end())
1296 it->second.print(os);
1300 LogicalResult AliasState::getAlias(
Type ty, raw_ostream &os)
const {
1302 if (it == attrTypeToAlias.end())
1304 if (!it->second.isPrinted)
1307 it->second.print(os);
1311 void AliasState::printAliases(
AsmPrinter::Impl &p, NewLineCounter &newLine,
1313 auto filterFn = [=](
const auto &aliasIt) {
1314 return aliasIt.second.canBeDeferred() == isDeferred;
1316 for (
auto &[opaqueSymbol, alias] :
1317 llvm::make_filter_range(attrTypeToAlias, filterFn)) {
1321 if (alias.isTypeAlias()) {
1324 alias.isPrinted =
true;
1351 class SSANameState {
1354 enum :
unsigned { NameSentinel = ~0U };
1357 SSANameState() =
default;
1362 void printValueID(
Value value,
bool printResultNo, raw_ostream &stream)
const;
1365 void printOperationID(
Operation *op, raw_ostream &stream)
const;
1372 BlockInfo getBlockInfo(
Block *block);
1381 void numberValuesInRegion(
Region ®ion);
1382 void numberValuesInBlock(
Block &block);
1389 void getResultIDAndNumber(
OpResult result,
Value &lookupValue,
1390 std::optional<int> &lookupResultNo)
const;
1393 void setValueName(
Value value, StringRef name);
1397 StringRef uniqueValueName(StringRef name);
1420 llvm::ScopedHashTable<StringRef, char> usedNames;
1421 llvm::BumpPtrAllocator usedNameAllocator;
1424 unsigned nextValueID = 0;
1426 unsigned nextArgumentID = 0;
1428 unsigned nextConflictID = 0;
1437 : printerFlags(printerFlags) {
1438 llvm::SaveAndRestore valueIDSaver(nextValueID);
1439 llvm::SaveAndRestore argumentIDSaver(nextArgumentID);
1440 llvm::SaveAndRestore conflictIDSaver(nextConflictID);
1445 using UsedNamesScopeTy = llvm::ScopedHashTable<StringRef, char>::ScopeTy;
1446 using NamingContext =
1447 std::tuple<Region *, unsigned, unsigned, unsigned, UsedNamesScopeTy *>;
1450 llvm::BumpPtrAllocator allocator;
1453 auto *topLevelNamesScope =
1454 new (allocator.Allocate<UsedNamesScopeTy>()) UsedNamesScopeTy(usedNames);
1458 nameContext.push_back(std::make_tuple(®ion, nextValueID, nextArgumentID,
1459 nextConflictID, topLevelNamesScope));
1461 numberValuesInOp(*op);
1463 while (!nameContext.empty()) {
1465 UsedNamesScopeTy *parentScope;
1469 std::tie(region, std::ignore, std::ignore, std::ignore, parentScope) =
1470 nameContext.pop_back_val();
1472 std::tie(region, nextValueID, nextArgumentID, nextConflictID,
1473 parentScope) = nameContext.pop_back_val();
1477 while (usedNames.getCurScope() != parentScope) {
1478 usedNames.getCurScope()->~UsedNamesScopeTy();
1479 assert((usedNames.getCurScope() !=
nullptr || parentScope ==
nullptr) &&
1480 "top level parentScope must be a nullptr");
1484 auto *curNamesScope =
new (allocator.Allocate<UsedNamesScopeTy>())
1485 UsedNamesScopeTy(usedNames);
1487 numberValuesInRegion(*region);
1491 nameContext.push_back(std::make_tuple(®ion, nextValueID,
1492 nextArgumentID, nextConflictID,
1497 while (usedNames.getCurScope() !=
nullptr)
1498 usedNames.getCurScope()->~UsedNamesScopeTy();
1501 void SSANameState::printValueID(
Value value,
bool printResultNo,
1502 raw_ostream &stream)
const {
1504 stream <<
"<<NULL VALUE>>";
1508 std::optional<int> resultNo;
1509 auto lookupValue = value;
1513 if (
OpResult result = dyn_cast<OpResult>(value))
1514 getResultIDAndNumber(result, lookupValue, resultNo);
1516 auto it = valueIDs.find(lookupValue);
1517 if (it == valueIDs.end()) {
1518 stream <<
"<<UNKNOWN SSA VALUE>>";
1523 if (it->second != NameSentinel) {
1524 stream << it->second;
1526 auto nameIt = valueNames.find(lookupValue);
1527 assert(nameIt != valueNames.end() &&
"Didn't have a name entry?");
1528 stream << nameIt->second;
1531 if (resultNo && printResultNo)
1532 stream <<
'#' << *resultNo;
1535 void SSANameState::printOperationID(
Operation *op, raw_ostream &stream)
const {
1536 auto it = operationIDs.find(op);
1537 if (it == operationIDs.end()) {
1538 stream <<
"<<UNKNOWN OPERATION>>";
1540 stream <<
'%' << it->second;
1545 auto it = opResultGroups.find(op);
1546 return it == opResultGroups.end() ?
ArrayRef<int>() : it->second;
1549 BlockInfo SSANameState::getBlockInfo(
Block *block) {
1550 auto it = blockNames.find(block);
1551 BlockInfo invalidBlock{-1,
"INVALIDBLOCK"};
1552 return it != blockNames.end() ? it->second : invalidBlock;
1555 void SSANameState::shadowRegionArgs(
Region ®ion,
ValueRange namesToUse) {
1556 assert(!region.
empty() &&
"cannot shadow arguments of an empty region");
1558 "incorrect number of names passed in");
1560 "only KnownIsolatedFromAbove ops can shadow names");
1563 for (
unsigned i = 0, e = namesToUse.size(); i != e; ++i) {
1564 auto nameToUse = namesToUse[i];
1565 if (nameToUse ==
nullptr)
1570 llvm::raw_svector_ostream nameStream(nameStr);
1571 printValueID(nameToUse,
true, nameStream);
1574 assert(valueIDs[nameToReplace] == NameSentinel);
1577 auto name = StringRef(nameStream.str()).drop_front();
1580 valueNames[nameToReplace] = name.copy(usedNameAllocator);
1586 StringRef maybeGetValueNameFromLoc(
Value value, StringRef name) {
1588 return maybeNameLoc.getName();
1593 void SSANameState::numberValuesInRegion(
Region ®ion) {
1595 bool opAsmOpInterfaceUsed =
false;
1596 auto setBlockArgNameFn = [&](
Value arg, StringRef name) {
1597 assert(!valueIDs.count(arg) &&
"arg numbered multiple times");
1598 assert(llvm::cast<BlockArgument>(arg).getOwner()->getParent() == ®ion &&
1599 "arg not defined in current region");
1600 opAsmOpInterfaceUsed =
true;
1602 name = maybeGetValueNameFromLoc(arg, name);
1603 setValueName(arg, name);
1608 if (
auto asmInterface = dyn_cast<OpAsmOpInterface>(op))
1609 asmInterface.getAsmBlockArgumentNames(region, setBlockArgNameFn);
1611 if (!opAsmOpInterfaceUsed) {
1613 if (
auto interface = dyn_cast<OpAsmTypeInterface>(arg.
getType())) {
1614 interface.getAsmName(
1615 [&](StringRef name) { setBlockArgNameFn(arg, name); });
1623 unsigned nextBlockID = 0;
1624 for (
auto &block : region) {
1627 auto blockInfoIt = blockNames.insert({&block, {-1,
""}});
1628 if (blockInfoIt.second) {
1632 llvm::raw_string_ostream(name) <<
"^bb" << nextBlockID;
1633 blockInfoIt.first->second.name = StringRef(name).copy(usedNameAllocator);
1635 blockInfoIt.first->second.ordering = nextBlockID++;
1637 numberValuesInBlock(block);
1641 void SSANameState::numberValuesInBlock(
Block &block) {
1646 llvm::raw_svector_ostream specialName(specialNameBuffer);
1648 if (valueIDs.count(arg))
1651 specialNameBuffer.resize(strlen(
"arg"));
1652 specialName << nextArgumentID++;
1654 StringRef specialNameStr = specialName.str();
1656 specialNameStr = maybeGetValueNameFromLoc(arg, specialNameStr);
1657 setValueName(arg, specialNameStr);
1661 for (
auto &op : block)
1662 numberValuesInOp(op);
1665 void SSANameState::numberValuesInOp(
Operation &op) {
1669 bool opAsmOpInterfaceUsed =
false;
1670 auto setResultNameFn = [&](
Value result, StringRef name) {
1671 assert(!valueIDs.count(result) &&
"result numbered multiple times");
1672 assert(result.
getDefiningOp() == &op &&
"result not defined by 'op'");
1673 opAsmOpInterfaceUsed =
true;
1675 name = maybeGetValueNameFromLoc(result, name);
1676 setValueName(result, name);
1679 if (
int resultNo = llvm::cast<OpResult>(result).getResultNumber())
1680 resultGroups.push_back(resultNo);
1683 auto setBlockNameFn = [&](
Block *block, StringRef name) {
1685 "getAsmBlockArgumentNames callback invoked on a block not directly "
1686 "nested under the current operation");
1687 assert(!blockNames.count(block) &&
"block numbered multiple times");
1690 if (name.data() != tmpBuffer.data()) {
1691 tmpBuffer.append(name);
1692 name = tmpBuffer.str();
1694 name = name.copy(usedNameAllocator);
1695 blockNames[block] = {-1, name};
1699 if (OpAsmOpInterface asmInterface = dyn_cast<OpAsmOpInterface>(&op)) {
1700 asmInterface.getAsmBlockNames(setBlockNameFn);
1701 asmInterface.getAsmResultNames(setResultNameFn);
1703 if (!opAsmOpInterfaceUsed) {
1706 bool allHaveOpAsmTypeInterface =
1708 return isa<OpAsmTypeInterface>(type);
1710 if (allHaveOpAsmTypeInterface) {
1712 auto interface = cast<OpAsmTypeInterface>(result.
getType());
1713 interface.getAsmName(
1714 [&](StringRef name) { setResultNameFn(result, name); });
1721 if (numResults == 0) {
1724 if (operationIDs.try_emplace(&op, nextValueID).second)
1733 setValueName(resultBegin, nameLoc.getName());
1738 if (valueIDs.try_emplace(resultBegin, nextValueID).second)
1742 if (resultGroups.size() != 1) {
1743 llvm::array_pod_sort(resultGroups.begin(), resultGroups.end());
1744 opResultGroups.try_emplace(&op, std::move(resultGroups));
1748 void SSANameState::getResultIDAndNumber(
1750 std::optional<int> &lookupResultNo)
const {
1758 auto resultGroupIt = opResultGroups.find(owner);
1759 if (resultGroupIt == opResultGroups.end()) {
1761 lookupResultNo = resultNo;
1768 const auto *it = llvm::upper_bound(resultGroups, resultNo);
1769 int groupResultNo = 0, groupSize = 0;
1772 if (it == resultGroups.end()) {
1773 groupResultNo = resultGroups.back();
1774 groupSize =
static_cast<int>(owner->
getNumResults()) - resultGroups.back();
1777 groupResultNo = *std::prev(it);
1778 groupSize = *it - groupResultNo;
1783 lookupResultNo = resultNo - groupResultNo;
1784 lookupValue = owner->
getResult(groupResultNo);
1787 void SSANameState::setValueName(
Value value, StringRef name) {
1790 valueIDs[value] = nextValueID++;
1794 valueIDs[value] = NameSentinel;
1795 valueNames[value] = uniqueValueName(name);
1798 StringRef SSANameState::uniqueValueName(StringRef name) {
1803 if (!usedNames.count(name)) {
1804 name = name.copy(usedNameAllocator);
1810 probeName.push_back(
'_');
1812 probeName += llvm::utostr(nextConflictID++);
1813 if (!usedNames.count(probeName)) {
1814 name = probeName.str().copy(usedNameAllocator);
1817 probeName.resize(name.size() + 1);
1821 usedNames.insert(name,
char());
1831 class DistinctState {
1837 uint64_t distinctCounter = 0;
1842 uint64_t DistinctState::getId(
DistinctAttr distinctAttr) {
1843 auto [it, inserted] =
1844 distinctAttrMap.try_emplace(distinctAttr, distinctCounter);
1847 return it->getSecond();
1854 AsmParsedResourceEntry::~AsmParsedResourceEntry() =
default;
1855 AsmResourceBuilder::~AsmResourceBuilder() =
default;
1856 AsmResourceParser::~AsmResourceParser() =
default;
1857 AsmResourcePrinter::~AsmResourcePrinter() =
default;
1861 case AsmResourceEntryKind::Blob:
1863 case AsmResourceEntryKind::Bool:
1865 case AsmResourceEntryKind::String:
1868 llvm_unreachable(
"unknown AsmResourceEntryKind");
1872 std::unique_ptr<ResourceCollection> &collection = keyToResources[key.str()];
1874 collection = std::make_unique<ResourceCollection>(key);
1878 std::vector<std::unique_ptr<AsmResourcePrinter>>
1880 std::vector<std::unique_ptr<AsmResourcePrinter>> printers;
1881 for (
auto &it : keyToResources) {
1882 ResourceCollection *collection = it.second.get();
1884 return collection->buildResources(op, builder);
1886 printers.emplace_back(
1892 LogicalResult FallbackAsmResourceMap::ResourceCollection::parseResource(
1896 FailureOr<AsmResourceBlob> blob = entry.
parseAsBlob();
1899 resources.emplace_back(entry.
getKey(), std::move(*blob));
1906 resources.emplace_back(entry.
getKey(), *value);
1913 resources.emplace_back(entry.
getKey(), std::move(*str));
1920 void FallbackAsmResourceMap::ResourceCollection::buildResources(
1922 for (
const auto &entry : resources) {
1923 if (
const auto *value = std::get_if<AsmResourceBlob>(&entry.value))
1925 else if (
const auto *value = std::get_if<bool>(&entry.value))
1927 else if (
const auto *value = std::get_if<std::string>(&entry.value))
1930 llvm_unreachable(
"unknown AsmResourceEntryKind");
1944 : interfaces(op->
getContext()), nameState(op, printerFlags),
1945 printerFlags(printerFlags), locationMap(locationMap) {}
1948 : interfaces(ctx), printerFlags(printerFlags), locationMap(locationMap) {}
1952 aliasState.initialize(op, printerFlags, interfaces);
1972 return llvm::make_pointee_range(externalResourcePrinters);
1982 (*locationMap)[op] = std::make_pair(line, col);
1988 return dialectResources;
1992 return success(cyclicPrintingStack.insert(opaquePointer));
2008 AliasState aliasState;
2011 SSANameState nameState;
2014 DistinctState distinctState;
2030 template <
typename Range>
2034 [&stream](
const auto &dimSize) {
2035 if (ShapedType::isDynamic(dimSize))
2053 return printerFlags;
2057 auto parentThreadId = llvm::get_threadid();
2059 if (parentThreadId == llvm::get_threadid()) {
2061 diag.print(llvm::dbgs());
2062 llvm::dbgs() <<
"\n";
2068 if (failed(
verify(op))) {
2069 LLVM_DEBUG(llvm::dbgs()
2071 <<
"' failed to verify and will be printed in generic form\n");
2075 return printerFlags;
2094 return impl->getPrinterFlags();
2098 std::unique_ptr<AsmResourcePrinter> printer) {
2099 impl->externalResourcePrinters.emplace_back(std::move(printer));
2104 return impl->getDialectResources();
2112 : os(os), state(state), printerFlags(state.getPrinterFlags()) {}
2120 printLocation(loc, allowAlias);
2126 if (!isTopLevel && succeeded(state.getAliasState().getAlias(loc, os)))
2130 .Case<OpaqueLoc>([&](OpaqueLoc loc) {
2131 printLocationInternal(loc.getFallbackLocation(), pretty);
2133 .Case<UnknownLoc>([&](UnknownLoc loc) {
2141 os << loc.getFilename().getValue();
2143 printEscapedString(loc.getFilename());
2144 if (loc.getEndColumn() == loc.getStartColumn() &&
2145 loc.getStartLine() == loc.getEndLine()) {
2146 os <<
':' << loc.getStartLine() <<
':' << loc.getStartColumn();
2149 if (loc.getStartLine() == loc.getEndLine()) {
2150 os <<
':' << loc.getStartLine() <<
':' << loc.getStartColumn()
2151 <<
" to :" << loc.getEndColumn();
2154 os <<
':' << loc.getStartLine() <<
':' << loc.getStartColumn() <<
" to "
2155 << loc.getEndLine() <<
':' << loc.getEndColumn();
2157 .Case<NameLoc>([&](NameLoc loc) {
2158 printEscapedString(loc.getName());
2161 auto childLoc = loc.getChildLoc();
2162 if (!llvm::isa<UnknownLoc>(childLoc)) {
2164 printLocationInternal(childLoc, pretty);
2168 .Case<CallSiteLoc>([&](CallSiteLoc loc) {
2173 printLocationInternal(callee, pretty);
2175 if (llvm::isa<NameLoc>(callee)) {
2176 if (llvm::isa<FileLineColLoc>(caller)) {
2179 os << newLine <<
" at ";
2182 os << newLine <<
" at ";
2187 printLocationInternal(caller, pretty);
2191 .Case<FusedLoc>([&](
FusedLoc loc) {
2194 if (
Attribute metadata = loc.getMetadata()) {
2202 [&](Location loc) { printLocationInternal(loc, pretty); },
2203 [&]() { os << ", "; });
2206 .Default([&](LocationAttr loc) {
2207 // Assumes that this is a dialect-specific attribute and prints it
2209 printAttribute(loc);
2215 static void printFloatValue(const APFloat &apValue, raw_ostream &os,
2216 bool *printedHex = nullptr) {
2217 // We would like to output the FP constant value in exponential notation,
2218 // but we cannot do this if doing so will lose precision. Check here to
2219 // make sure that we only output it in exponential format if we can parse
2220 // the value back and get the same value.
2221 bool isInf = apValue.isInfinity();
2222 bool isNaN = apValue.isNaN();
2223 if (!isInf && !isNaN) {
2224 SmallString<128> strValue;
2225 apValue.toString(strValue, /*FormatPrecision=*/6, /*FormatMaxPadding=*/0,
2226 /*TruncateZero=*/false);
2228 // Check to make sure that the stringized number is not some string like
2229 // "Inf" or NaN, that atof will accept, but the lexer will not. Check
2230 // that the string matches the "[-+]?[0-9]" regex.
2231 assert(((strValue[0] >= '0
' && strValue[0] <= '9') ||
2232 ((strValue[0] ==
'-' || strValue[0] ==
'+') &&
2233 (strValue[1] >=
'0' && strValue[1] <=
'9'))) &&
2234 "[-+]?[0-9] regex does not match!");
2238 if (APFloat(apValue.getSemantics(), strValue).bitwiseIsEqual(apValue)) {
2246 apValue.toString(strValue);
2249 if (strValue.str().contains(
'.')) {
2260 APInt apInt = apValue.bitcastToAPInt();
2261 apInt.toString(str, 16,
false,
2268 return printLocationInternal(loc,
true,
true);
2272 printLocationInternal(loc,
false,
true);
2281 if (symName.empty() || !isalpha(symName.front()))
2286 symName = symName.drop_while(
2287 [](
char c) {
return llvm::isAlnum(c) || c ==
'.' || c ==
'_'; });
2288 if (symName.empty())
2293 return symName.front() ==
'<' && symName.back() ==
'>';
2298 StringRef dialectName, StringRef symString) {
2299 os << symPrefix << dialectName;
2304 os <<
'.' << symString;
2308 os << '<' << symString << '>
';
2312 static bool isBareIdentifier(StringRef name) {
2313 // By making this unsigned, the value passed in to isalnum will always be
2314 // in the range 0-255. This is important when building with MSVC because
2315 // its implementation will assert. This situation can arise when dealing
2316 // with UTF-8 multibyte characters.
2317 if (name.empty() || (!isalpha(name[0]) && name[0] != '_
'))
2319 return llvm::all_of(name.drop_front(), [](unsigned char c) {
2320 return isalnum(c) || c == '_
' || c == '$
' || c == '.
';
2326 static void printKeywordOrString(StringRef keyword, raw_ostream &os) {
2327 // If it can be represented as a bare identifier, write it directly.
2328 if (isBareIdentifier(keyword)) {
2333 // Otherwise, output the keyword wrapped in quotes with proper escaping.
2335 printEscapedString(keyword, os);
2342 static void printSymbolReference(StringRef symbolRef, raw_ostream &os) {
2343 if (symbolRef.empty()) {
2344 os << "@<<INVALID EMPTY SYMBOL>>
";
2348 printKeywordOrString(symbolRef, os);
2351 // Print out a valid ElementsAttr that is succinct and can represent any
2352 // potential shape/type, for use when eliding a large ElementsAttr.
2354 // We choose to use a dense resource ElementsAttr literal with conspicuous
2355 // content to hopefully alert readers to the fact that this has been elided.
2356 static void printElidedElementsAttr(raw_ostream &os) {
2357 os << R"(dense_resource<__elided__>)
";
2360 void AsmPrinter::Impl::printResourceHandle(
2361 const AsmDialectResourceHandle &resource) {
2362 auto *interface = cast<OpAsmDialectInterface>(resource.getDialect());
2363 ::printKeywordOrString(interface->getResourceKey(resource), os);
2364 state.getDialectResources()[resource.getDialect()].insert(resource);
2367 LogicalResult AsmPrinter::Impl::printAlias(Attribute attr) {
2368 return state.getAliasState().getAlias(attr, os);
2371 LogicalResult AsmPrinter::Impl::printAlias(Type type) {
2372 return state.getAliasState().getAlias(type, os);
2375 void AsmPrinter::Impl::printAttribute(Attribute attr,
2376 AttrTypeElision typeElision) {
2378 os << "<<NULL ATTRIBUTE>>
";
2382 // Try to print an alias for this attribute.
2383 if (succeeded(printAlias(attr)))
2385 return printAttributeImpl(attr, typeElision);
2388 void AsmPrinter::Impl::printAttributeImpl(Attribute attr,
2389 AttrTypeElision typeElision) {
2390 if (!isa<BuiltinDialect>(attr.getDialect())) {
2391 printDialectAttribute(attr);
2392 } else if (auto opaqueAttr = llvm::dyn_cast<OpaqueAttr>(attr)) {
2393 printDialectSymbol(os, "#
", opaqueAttr.getDialectNamespace(),
2394 opaqueAttr.getAttrData());
2395 } else if (llvm::isa<UnitAttr>(attr)) {
2398 } else if (auto distinctAttr = llvm::dyn_cast<DistinctAttr>(attr)) {
2399 os << "distinct[
" << state.getDistinctState().getId(distinctAttr) << "]<
";
2400 if (!llvm::isa<UnitAttr>(distinctAttr.getReferencedAttr())) {
2401 printAttribute(distinctAttr.getReferencedAttr());
2405 } else if (auto dictAttr = llvm::dyn_cast<DictionaryAttr>(attr)) {
2407 interleaveComma(dictAttr.getValue(),
2408 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2411 } else if (auto intAttr = llvm::dyn_cast<IntegerAttr>(attr)) {
2412 Type intType = intAttr.getType();
2413 if (intType.isSignlessInteger(1)) {
2414 os << (intAttr.getValue().getBoolValue() ? "true" : "false");
2416 // Boolean integer attributes always elides the type.
2420 // Only print attributes as unsigned if they are explicitly unsigned or are
2421 // signless 1-bit values. Indexes, signed values, and multi-bit signless
2422 // values print as signed.
2424 intType.isUnsignedInteger() || intType.isSignlessInteger(1);
2425 intAttr.getValue().print(os, !isUnsigned);
2427 // IntegerAttr elides the type if I64.
2428 if (typeElision == AttrTypeElision::May && intType.isSignlessInteger(64))
2431 } else if (auto floatAttr = llvm::dyn_cast<FloatAttr>(attr)) {
2432 bool printedHex = false;
2433 printFloatValue(floatAttr.getValue(), os, &printedHex);
2435 // FloatAttr elides the type if F64.
2436 if (typeElision == AttrTypeElision::May && floatAttr.getType().isF64() &&
2440 } else if (auto strAttr = llvm::dyn_cast<StringAttr>(attr)) {
2441 printEscapedString(strAttr.getValue());
2443 } else if (auto arrayAttr = llvm::dyn_cast<ArrayAttr>(attr)) {
2445 interleaveComma(arrayAttr.getValue(), [&](Attribute attr) {
2446 printAttribute(attr, AttrTypeElision::May);
2450 } else if (auto affineMapAttr = llvm::dyn_cast<AffineMapAttr>(attr)) {
2451 os << "affine_map<
";
2452 affineMapAttr.getValue().print(os);
2455 // AffineMap always elides the type.
2458 } else if (auto integerSetAttr = llvm::dyn_cast<IntegerSetAttr>(attr)) {
2459 os << "affine_set<
";
2460 integerSetAttr.getValue().print(os);
2463 // IntegerSet always elides the type.
2466 } else if (auto typeAttr = llvm::dyn_cast<TypeAttr>(attr)) {
2467 printType(typeAttr.getValue());
2469 } else if (auto refAttr = llvm::dyn_cast<SymbolRefAttr>(attr)) {
2470 printSymbolReference(refAttr.getRootReference().getValue(), os);
2471 for (FlatSymbolRefAttr nestedRef : refAttr.getNestedReferences()) {
2473 printSymbolReference(nestedRef.getValue(), os);
2476 } else if (auto intOrFpEltAttr =
2477 llvm::dyn_cast<DenseIntOrFPElementsAttr>(attr)) {
2478 if (printerFlags.shouldElideElementsAttr(intOrFpEltAttr)) {
2479 printElidedElementsAttr(os);
2482 printDenseIntOrFPElementsAttr(intOrFpEltAttr, /*allowHex=*/true);
2486 } else if (auto strEltAttr = llvm::dyn_cast<DenseStringElementsAttr>(attr)) {
2487 if (printerFlags.shouldElideElementsAttr(strEltAttr)) {
2488 printElidedElementsAttr(os);
2491 printDenseStringElementsAttr(strEltAttr);
2495 } else if (auto sparseEltAttr = llvm::dyn_cast<SparseElementsAttr>(attr)) {
2496 if (printerFlags.shouldElideElementsAttr(sparseEltAttr.getIndices()) ||
2497 printerFlags.shouldElideElementsAttr(sparseEltAttr.getValues())) {
2498 printElidedElementsAttr(os);
2501 DenseIntElementsAttr indices = sparseEltAttr.getIndices();
2502 if (indices.getNumElements() != 0) {
2503 printDenseIntOrFPElementsAttr(indices, /*allowHex=*/false);
2505 printDenseElementsAttr(sparseEltAttr.getValues(), /*allowHex=*/true);
2509 } else if (auto stridedLayoutAttr = llvm::dyn_cast<StridedLayoutAttr>(attr)) {
2510 stridedLayoutAttr.print(os);
2511 } else if (auto denseArrayAttr = llvm::dyn_cast<DenseArrayAttr>(attr)) {
2513 printType(denseArrayAttr.getElementType());
2514 if (!denseArrayAttr.empty()) {
2516 printDenseArrayAttr(denseArrayAttr);
2520 } else if (auto resourceAttr =
2521 llvm::dyn_cast<DenseResourceElementsAttr>(attr)) {
2522 os << "dense_resource<
";
2523 printResourceHandle(resourceAttr.getRawHandle());
2525 } else if (auto locAttr = llvm::dyn_cast<LocationAttr>(attr)) {
2526 printLocation(locAttr);
2528 llvm::report_fatal_error("Unknown builtin attribute
");
2530 // Don't print the type if we must elide it, or if it is a None type.
2531 if (typeElision != AttrTypeElision::Must) {
2532 if (auto typedAttr = llvm::dyn_cast<TypedAttr>(attr)) {
2533 Type attrType = typedAttr.getType();
2534 if (!llvm::isa<NoneType>(attrType)) {
2536 printType(attrType);
2543 static void printDenseIntElement(const APInt &value, raw_ostream &os,
2545 if (type.isInteger(1))
2546 os << (value.getBoolValue() ? "
true" : "false");
2548 value.print(os, !type.isUnsignedInteger());
2552 printDenseElementsAttrImpl(bool isSplat, ShapedType type, raw_ostream &os,
2553 function_ref<void(unsigned)> printEltFn) {
2554 // Special case for 0-d and splat tensors.
2556 return printEltFn(0);
2558 // Special case for degenerate tensors.
2559 auto numElements = type.getNumElements();
2560 if (numElements == 0)
2563 // We use a mixed-radix counter to iterate through the shape. When we bump a
2564 // non-least-significant digit, we emit a close bracket. When we next emit an
2565 // element we re-open all closed brackets.
2567 // The mixed-radix counter, with radices in 'shape'.
2568 int64_t rank = type.getRank();
2569 SmallVector<unsigned, 4> counter(rank, 0);
2570 // The number of brackets that have been opened and not closed.
2571 unsigned openBrackets = 0;
2573 auto shape = type.getShape();
2574 auto bumpCounter = [&] {
2575 // Bump the least significant digit.
2576 ++counter[rank - 1];
2577 // Iterate backwards bubbling back the increment.
2578 for (unsigned i = rank - 1; i > 0; --i)
2579 if (counter[i] >= shape[i]) {
2580 // Index 'i' is rolled over. Bump (i-1) and close a bracket.
2588 for (unsigned idx = 0, e = numElements; idx != e; ++idx) {
2591 while (openBrackets++ < rank)
2593 openBrackets = rank;
2597 while (openBrackets-- > 0)
2601 void AsmPrinter::Impl::printDenseElementsAttr(DenseElementsAttr attr,
2603 if (auto stringAttr = llvm::dyn_cast<DenseStringElementsAttr>(attr))
2604 return printDenseStringElementsAttr(stringAttr);
2606 printDenseIntOrFPElementsAttr(llvm::cast<DenseIntOrFPElementsAttr>(attr),
2610 void AsmPrinter::Impl::printDenseIntOrFPElementsAttr(
2611 DenseIntOrFPElementsAttr attr, bool allowHex) {
2612 auto type = attr.getType();
2613 auto elementType = type.getElementType();
2615 // Check to see if we should format this attribute as a hex string.
2616 if (allowHex && printerFlags.shouldPrintElementsAttrWithHex(attr)) {
2617 ArrayRef<char> rawData = attr.getRawData();
2618 if (llvm::endianness::native == llvm::endianness::big) {
2619 // Convert endianess in big-endian(BE) machines. `rawData` is BE in BE
2620 // machines. It is converted here to print in LE format.
2621 SmallVector<char, 64> outDataVec(rawData.size());
2622 MutableArrayRef<char> convRawData(outDataVec);
2623 DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
2624 rawData, convRawData, type);
2625 printHexString(convRawData);
2627 printHexString(rawData);
2633 if (ComplexType complexTy = llvm::dyn_cast<ComplexType>(elementType)) {
2634 Type complexElementType = complexTy.getElementType();
2635 // Note: The if and else below had a common lambda function which invoked
2636 // printDenseElementsAttrImpl. This lambda was hitting a bug in gcc 9.1,9.2
2637 // and hence was replaced.
2638 if (llvm::isa<IntegerType>(complexElementType)) {
2639 auto valueIt = attr.value_begin<std::complex<APInt>>();
2640 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2641 auto complexValue = *(valueIt + index);
2643 printDenseIntElement(complexValue.real(), os, complexElementType);
2645 printDenseIntElement(complexValue.imag(), os, complexElementType);
2649 auto valueIt = attr.value_begin<std::complex<APFloat>>();
2650 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2651 auto complexValue = *(valueIt + index);
2653 printFloatValue(complexValue.real(), os);
2655 printFloatValue(complexValue.imag(), os);
2659 } else if (elementType.isIntOrIndex()) {
2660 auto valueIt = attr.value_begin<APInt>();
2661 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2662 printDenseIntElement(*(valueIt + index), os, elementType);
2665 assert(llvm::isa<FloatType>(elementType) && "unexpected element type
");
2666 auto valueIt = attr.value_begin<APFloat>();
2667 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2668 printFloatValue(*(valueIt + index), os);
2673 void AsmPrinter::Impl::printDenseStringElementsAttr(
2674 DenseStringElementsAttr attr) {
2675 ArrayRef<StringRef> data = attr.getRawStringData();
2676 auto printFn = [&](unsigned index) { printEscapedString(data[index]); };
2677 printDenseElementsAttrImpl(attr.isSplat(), attr.getType(), os, printFn);
2680 void AsmPrinter::Impl::printDenseArrayAttr(DenseArrayAttr attr) {
2681 Type type = attr.getElementType();
2682 unsigned bitwidth = type.isInteger(1) ? 8 : type.getIntOrFloatBitWidth();
2683 unsigned byteSize = bitwidth / 8;
2684 ArrayRef<char> data = attr.getRawData();
2686 auto printElementAt = [&](unsigned i) {
2687 APInt value(bitwidth, 0);
2689 llvm::LoadIntFromMemory(
2690 value, reinterpret_cast<const uint8_t *>(data.begin() + byteSize * i),
2693 // Print the data as-is or as a float.
2694 if (type.isIntOrIndex()) {
2695 printDenseIntElement(value, getStream(), type);
2697 APFloat fltVal(llvm::cast<FloatType>(type).getFloatSemantics(), value);
2698 printFloatValue(fltVal, getStream());
2701 llvm::interleaveComma(llvm::seq<unsigned>(0, attr.size()), getStream(),
2705 void AsmPrinter::Impl::printType(Type type) {
2707 os << "<<NULL TYPE>>
";
2711 // Try to print an alias for this type.
2712 if (succeeded(printAlias(type)))
2714 return printTypeImpl(type);
2717 void AsmPrinter::Impl::printTypeImpl(Type type) {
2718 TypeSwitch<Type>(type)
2719 .Case<OpaqueType>([&](OpaqueType opaqueTy) {
2720 printDialectSymbol(os, "!
", opaqueTy.getDialectNamespace(),
2721 opaqueTy.getTypeData());
2723 .Case<IndexType>([&](Type) { os << "index
"; })
2724 .Case<Float4E2M1FNType>([&](Type) { os << "f4E2M1FN
"; })
2725 .Case<Float6E2M3FNType>([&](Type) { os << "f6E2M3FN
"; })
2726 .Case<Float6E3M2FNType>([&](Type) { os << "f6E3M2FN
"; })
2727 .Case<Float8E5M2Type>([&](Type) { os << "f8E5M2
"; })
2728 .Case<Float8E4M3Type>([&](Type) { os << "f8E4M3
"; })
2729 .Case<Float8E4M3FNType>([&](Type) { os << "f8E4M3FN
"; })
2730 .Case<Float8E5M2FNUZType>([&](Type) { os << "f8E5M2FNUZ
"; })
2731 .Case<Float8E4M3FNUZType>([&](Type) { os << "f8E4M3FNUZ
"; })
2732 .Case<Float8E4M3B11FNUZType>([&](Type) { os << "f8E4M3B11FNUZ
"; })
2733 .Case<Float8E3M4Type>([&](Type) { os << "f8E3M4
"; })
2734 .Case<Float8E8M0FNUType>([&](Type) { os << "f8E8M0FNU
"; })
2735 .Case<BFloat16Type>([&](Type) { os << "bf16"; })
2736 .Case<Float16Type>([&](Type) { os << "f16"; })
2737 .Case<FloatTF32Type>([&](Type) { os << "tf32
"; })
2738 .Case<Float32Type>([&](Type) { os << "f32
"; })
2739 .Case<Float64Type>([&](Type) { os << "f64
"; })
2740 .Case<Float80Type>([&](Type) { os << "f80
"; })
2741 .Case<Float128Type>([&](Type) { os << "f128
"; })
2742 .Case<IntegerType>([&](IntegerType integerTy) {
2743 if (integerTy.isSigned())
2745 else if (integerTy.isUnsigned())
2747 os << 'i' << integerTy.getWidth();
2749 .Case<FunctionType>([&](FunctionType funcTy) {
2751 interleaveComma(funcTy.getInputs(), [&](Type ty) { printType(ty); });
2753 ArrayRef<Type> results = funcTy.getResults();
2754 if (results.size() == 1 && !llvm::isa<FunctionType>(results[0])) {
2755 printType(results[0]);
2758 interleaveComma(results, [&](Type ty) { printType(ty); });
2762 .Case<VectorType>([&](VectorType vectorTy) {
2763 auto scalableDims = vectorTy.getScalableDims();
2765 auto vShape = vectorTy.getShape();
2766 unsigned lastDim = vShape.size();
2767 unsigned dimIdx = 0;
2768 for (dimIdx = 0; dimIdx < lastDim; dimIdx++) {
2769 if (!scalableDims.empty() && scalableDims[dimIdx])
2771 os << vShape[dimIdx];
2772 if (!scalableDims.empty() && scalableDims[dimIdx])
2776 printType(vectorTy.getElementType());
2779 .Case<RankedTensorType>([&](RankedTensorType tensorTy) {
2781 printDimensionList(tensorTy.getShape());
2782 if (!tensorTy.getShape().empty())
2784 printType(tensorTy.getElementType());
2785 // Only print the encoding attribute value if set.
2786 if (tensorTy.getEncoding()) {
2788 printAttribute(tensorTy.getEncoding());
2792 .Case<UnrankedTensorType>([&](UnrankedTensorType tensorTy) {
2794 printType(tensorTy.getElementType());
2797 .Case<MemRefType>([&](MemRefType memrefTy) {
2799 printDimensionList(memrefTy.getShape());
2800 if (!memrefTy.getShape().empty())
2802 printType(memrefTy.getElementType());
2803 MemRefLayoutAttrInterface layout = memrefTy.getLayout();
2804 if (!llvm::isa<AffineMapAttr>(layout) || !layout.isIdentity()) {
2806 printAttribute(memrefTy.getLayout(), AttrTypeElision::May);
2808 // Only print the memory space if it is the non-default one.
2809 if (memrefTy.getMemorySpace()) {
2811 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2815 .Case<UnrankedMemRefType>([&](UnrankedMemRefType memrefTy) {
2817 printType(memrefTy.getElementType());
2818 // Only print the memory space if it is the non-default one.
2819 if (memrefTy.getMemorySpace()) {
2821 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2825 .Case<ComplexType>([&](ComplexType complexTy) {
2827 printType(complexTy.getElementType());
2830 .Case<TupleType>([&](TupleType tupleTy) {
2832 interleaveComma(tupleTy.getTypes(),
2833 [&](Type type) { printType(type); });
2836 .Case<NoneType>([&](Type) { os << "none
"; })
2837 .Default([&](Type type) { return printDialectType(type); });
2840 void AsmPrinter::Impl::printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
2841 ArrayRef<StringRef> elidedAttrs,
2843 // If there are no attributes, then there is nothing to be done.
2847 // Functor used to print a filtered attribute list.
2848 auto printFilteredAttributesFn = [&](auto filteredAttrs) {
2849 // Print the 'attributes' keyword if necessary.
2851 os << " attributes
";
2853 // Otherwise, print them all out in braces.
2855 interleaveComma(filteredAttrs,
2856 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2860 // If no attributes are elided, we can directly print with no filtering.
2861 if (elidedAttrs.empty())
2862 return printFilteredAttributesFn(attrs);
2864 // Otherwise, filter out any attributes that shouldn't be included.
2865 llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
2867 auto filteredAttrs = llvm::make_filter_range(attrs, [&](NamedAttribute attr) {
2868 return !elidedAttrsSet.contains(attr.getName().strref());
2870 if (!filteredAttrs.empty())
2871 printFilteredAttributesFn(filteredAttrs);
2873 void AsmPrinter::Impl::printNamedAttribute(NamedAttribute attr) {
2874 // Print the name without quotes if possible.
2875 ::printKeywordOrString(attr.getName().strref(), os);
2877 // Pretty printing elides the attribute value for unit attributes.
2878 if (llvm::isa<UnitAttr>(attr.getValue()))
2882 printAttribute(attr.getValue());
2885 void AsmPrinter::Impl::printDialectAttribute(Attribute attr) {
2886 auto &dialect = attr.getDialect();
2888 // Ask the dialect to serialize the attribute to a string.
2889 std::string attrName;
2891 llvm::raw_string_ostream attrNameStr(attrName);
2892 Impl subPrinter(attrNameStr, state);
2893 DialectAsmPrinter printer(subPrinter);
2894 dialect.printAttribute(attr, printer);
2896 printDialectSymbol(os, "#
", dialect.getNamespace(), attrName);
2899 void AsmPrinter::Impl::printDialectType(Type type) {
2900 auto &dialect = type.getDialect();
2902 // Ask the dialect to serialize the type to a string.
2903 std::string typeName;
2905 llvm::raw_string_ostream typeNameStr(typeName);
2906 Impl subPrinter(typeNameStr, state);
2907 DialectAsmPrinter printer(subPrinter);
2908 dialect.printType(type, printer);
2910 printDialectSymbol(os, "!
", dialect.getNamespace(), typeName);
2913 void AsmPrinter::Impl::printEscapedString(StringRef str) {
2915 llvm::printEscapedString(str, os);
2920 os <<
"\"0x" << llvm::toHex(str) <<
"\"";
2923 printHexString(StringRef(data.data(), data.size()));
2927 return state.pushCyclicPrinting(opaquePointer);
2943 assert(
impl &&
"expected AsmPrinter::getStream to be overriden");
2944 return impl->getStream();
2949 assert(
impl &&
"expected AsmPrinter::printFloat to be overriden");
2954 assert(
impl &&
"expected AsmPrinter::printType to be overriden");
2955 impl->printType(type);
2959 assert(
impl &&
"expected AsmPrinter::printAttribute to be overriden");
2960 impl->printAttribute(attr);
2964 assert(
impl &&
"expected AsmPrinter::printAlias to be overriden");
2965 return impl->printAlias(attr);
2969 assert(
impl &&
"expected AsmPrinter::printAlias to be overriden");
2970 return impl->printAlias(type);
2975 "expected AsmPrinter::printAttributeWithoutType to be overriden");
2980 assert(
impl &&
"expected AsmPrinter::printKeywordOrString to be overriden");
2985 assert(
impl &&
"expected AsmPrinter::printString to be overriden");
2987 printEscapedString(keyword,
getStream());
2992 assert(
impl &&
"expected AsmPrinter::printSymbolName to be overriden");
2997 assert(
impl &&
"expected AsmPrinter::printResourceHandle to be overriden");
2998 impl->printResourceHandle(resource);
3006 return impl->pushCyclicPrinting(opaquePointer);
3017 printAffineExprInternal(expr, BindingStrength::Weak, printValueName);
3023 const char *binopSpelling =
nullptr;
3026 unsigned pos = cast<AffineSymbolExpr>(expr).getPosition();
3028 printValueName(pos,
true);
3034 unsigned pos = cast<AffineDimExpr>(expr).getPosition();
3036 printValueName(pos,
false);
3042 os << cast<AffineConstantExpr>(expr).getValue();
3045 binopSpelling =
" + ";
3048 binopSpelling =
" * ";
3051 binopSpelling =
" floordiv ";
3054 binopSpelling =
" ceildiv ";
3057 binopSpelling =
" mod ";
3061 auto binOp = cast<AffineBinaryOpExpr>(expr);
3067 if (enclosingTightness == BindingStrength::Strong)
3071 auto rhsConst = dyn_cast<AffineConstantExpr>(rhsExpr);
3073 rhsConst.getValue() == -1) {
3075 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
3076 if (enclosingTightness == BindingStrength::Strong)
3081 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
3083 os << binopSpelling;
3084 printAffineExprInternal(rhsExpr, BindingStrength::Strong, printValueName);
3086 if (enclosingTightness == BindingStrength::Strong)
3092 if (enclosingTightness == BindingStrength::Strong)
3097 if (
auto rhs = dyn_cast<AffineBinaryOpExpr>(rhsExpr)) {
3100 if (
auto rrhs = dyn_cast<AffineConstantExpr>(rrhsExpr)) {
3101 if (rrhs.getValue() == -1) {
3102 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
3106 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
3109 printAffineExprInternal(rhs.getLHS(), BindingStrength::Weak,
3113 if (enclosingTightness == BindingStrength::Strong)
3118 if (rrhs.getValue() < -1) {
3119 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
3122 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
3124 os <<
" * " << -rrhs.getValue();
3125 if (enclosingTightness == BindingStrength::Strong)
3134 if (
auto rhsConst = dyn_cast<AffineConstantExpr>(rhsExpr)) {
3135 if (rhsConst.getValue() < 0) {
3136 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
3137 os <<
" - " << -rhsConst.getValue();
3138 if (enclosingTightness == BindingStrength::Strong)
3144 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
3147 printAffineExprInternal(rhsExpr, BindingStrength::Weak, printValueName);
3149 if (enclosingTightness == BindingStrength::Strong)
3154 printAffineExprInternal(expr, BindingStrength::Weak);
3155 isEq ? os <<
" == 0" : os <<
" >= 0";
3161 for (
int i = 0; i < (int)map.
getNumDims() - 1; ++i)
3162 os <<
'd' << i <<
", ";
3171 os <<
's' << i <<
", ";
3180 [&](
AffineExpr expr) { printAffineExpr(expr); });
3187 for (
unsigned i = 1; i < set.
getNumDims(); ++i)
3188 os <<
'd' << i - 1 <<
", ";
3197 os <<
's' << i <<
", ";
3206 for (
int i = 1; i < numConstraints; ++i) {
3210 if (numConstraints >= 1)
3211 printAffineConstraint(set.
getConstraint(numConstraints - 1),
3212 set.
isEq(numConstraints - 1));
3227 explicit OperationPrinter(raw_ostream &os,
AsmStateImpl &state)
3231 void printTopLevelOperation(
Operation *op);
3235 void printFullOpWithIndentAndLoc(
Operation *op);
3241 void printCustomOrGenericOp(
Operation *op)
override;
3243 void printGenericOp(
Operation *op,
bool printOpName)
override;
3246 void printBlockName(
Block *block);
3251 void print(
Block *block,
bool printBlockArgs =
true,
3252 bool printBlockTerminator =
true);
3255 void printValueID(
Value value,
bool printResultNo =
true,
3256 raw_ostream *streamOverride =
nullptr)
const;
3260 raw_ostream *streamOverride =
nullptr)
const;
3268 void printOptionalLocationSpecifier(
Location loc)
override {
3269 printTrailingLocation(loc);
3276 os.indent(currentIndent);
3280 void increaseIndent()
override { currentIndent += indentWidth; }
3283 void decreaseIndent()
override { currentIndent -= indentWidth; }
3292 bool omitType =
false)
override;
3295 void printOperand(
Value value)
override { printValueID(value); }
3296 void printOperand(
Value value, raw_ostream &os)
override {
3297 printValueID(value,
true, &os);
3305 void printOptionalAttrDictWithKeyword(
3313 void printSuccessor(
Block *successor)
override;
3317 void printSuccessorAndUseList(
Block *successor,
3322 bool printBlockTerminators,
bool printEmptyBlock)
override;
3329 state.getSSANameState().shadowRegionArgs(region, namesToUse);
3334 void printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3349 void printValueUsers(
Value value);
3353 void printUserIDs(
Operation *user,
bool prefixComma =
false);
3361 using PrintFn =
function_ref<void(StringRef, ValueFn)>;
3363 ResourceBuilder(PrintFn printFn) : printFn(printFn) {}
3364 ~ResourceBuilder()
override =
default;
3366 void buildBool(StringRef key,
bool data)
final {
3367 printFn(key, [&](raw_ostream &os) { os << (data ?
"true" :
"false"); });
3370 void buildString(StringRef key, StringRef data)
final {
3371 printFn(key, [&](raw_ostream &os) {
3373 llvm::printEscapedString(data, os);
3379 uint32_t dataAlignment)
final {
3380 printFn(key, [&](raw_ostream &os) {
3382 llvm::support::ulittle32_t dataAlignmentLE(dataAlignment);
3384 << llvm::toHex(StringRef(
reinterpret_cast<char *
>(&dataAlignmentLE),
3385 sizeof(dataAlignment)))
3386 << llvm::toHex(StringRef(data.data(), data.size())) <<
"\"";
3395 void printFileMetadataDictionary(
Operation *op);
3401 void printResourceFileMetadata(
function_ref<
void()> checkAddMetadataDict,
3412 const static unsigned indentWidth = 2;
3415 unsigned currentIndent = 0;
3419 void OperationPrinter::printTopLevelOperation(
Operation *op) {
3421 state.getAliasState().printNonDeferredAliases(*
this, newLine);
3424 printFullOpWithIndentAndLoc(op);
3428 state.getAliasState().printDeferredAliases(*
this, newLine);
3431 printFileMetadataDictionary(op);
3434 void OperationPrinter::printFileMetadataDictionary(
Operation *op) {
3435 bool sawMetadataEntry =
false;
3436 auto checkAddMetadataDict = [&] {
3437 if (!std::exchange(sawMetadataEntry,
true))
3438 os << newLine <<
"{-#" << newLine;
3442 printResourceFileMetadata(checkAddMetadataDict, op);
3445 if (sawMetadataEntry)
3446 os << newLine <<
"#-}" << newLine;
3449 void OperationPrinter::printResourceFileMetadata(
3452 bool hadResource =
false;
3453 bool needResourceComma =
false;
3454 bool needEntryComma =
false;
3455 auto processProvider = [&](StringRef dictName, StringRef name,
auto &provider,
3456 auto &&...providerArgs) {
3457 bool hadEntry =
false;
3458 auto printFn = [&](StringRef key, ResourceBuilder::ValueFn valueFn) {
3459 checkAddMetadataDict();
3461 std::string resourceStr;
3462 auto printResourceStr = [&](raw_ostream &os) { os << resourceStr; };
3463 std::optional<uint64_t> charLimit =
3465 if (charLimit.has_value()) {
3466 llvm::raw_string_ostream ss(resourceStr);
3470 if (resourceStr.size() > charLimit.value())
3474 valueFn = printResourceStr;
3478 if (!std::exchange(hadResource,
true)) {
3479 if (needResourceComma)
3480 os <<
"," << newLine;
3481 os <<
" " << dictName <<
"_resources: {" << newLine;
3484 if (!std::exchange(hadEntry,
true)) {
3486 os <<
"," << newLine;
3487 os <<
" " << name <<
": {" << newLine;
3489 os <<
"," << newLine;
3497 ResourceBuilder entryBuilder(printFn);
3498 provider.buildResources(op, providerArgs..., entryBuilder);
3500 needEntryComma |= hadEntry;
3502 os << newLine <<
" }";
3508 auto &dialectResources = state.getDialectResources();
3509 StringRef name = interface.getDialect()->getNamespace();
3510 auto it = dialectResources.find(interface.getDialect());
3511 if (it != dialectResources.end())
3512 processProvider(
"dialect", name, interface, it->second);
3514 processProvider(
"dialect", name, interface,
3518 os << newLine <<
" }";
3522 needEntryComma =
false;
3523 needResourceComma = hadResource;
3524 hadResource =
false;
3525 for (
const auto &printer : state.getResourcePrinters())
3526 processProvider(
"external", printer.getName(), printer);
3528 os << newLine <<
" }";
3536 void OperationPrinter::printRegionArgument(
BlockArgument arg,
3544 printOptionalAttrDict(argAttrs);
3546 printTrailingLocation(arg.
getLoc(),
false);
3549 void OperationPrinter::printFullOpWithIndentAndLoc(
Operation *op) {
3551 state.registerOperationLocation(op, newLine.curLine, currentIndent);
3553 os.indent(currentIndent);
3555 printTrailingLocation(op->
getLoc());
3557 printUsersComment(op);
3560 void OperationPrinter::printFullOp(
Operation *op) {
3562 auto printResultGroup = [&](
size_t resultNo,
size_t resultCount) {
3563 printValueID(op->
getResult(resultNo),
false);
3564 if (resultCount > 1)
3565 os <<
':' << resultCount;
3569 ArrayRef<int> resultGroups = state.getSSANameState().getOpResultGroups(op);
3570 if (!resultGroups.empty()) {
3573 interleaveComma(llvm::seq<int>(0, resultGroups.size() - 1), [&](
int i) {
3574 printResultGroup(resultGroups[i],
3575 resultGroups[i + 1] - resultGroups[i]);
3578 printResultGroup(resultGroups.back(), numResults - resultGroups.back());
3581 printResultGroup(0, numResults);
3587 printCustomOrGenericOp(op);
3590 void OperationPrinter::printUsersComment(
Operation *op) {
3594 printOperationID(op);
3595 }
else if (numResults && op->
use_empty()) {
3597 }
else if (numResults && !op->
use_empty()) {
3600 unsigned usedInNResults = 0;
3601 unsigned usedInNOperations = 0;
3604 if (userSet.insert(user).second) {
3605 ++usedInNOperations;
3606 usedInNResults += user->getNumResults();
3611 bool exactlyOneUniqueUse =
3612 usedInNResults <= 1 && usedInNOperations <= 1 && numResults == 1;
3613 os <<
" // " << (exactlyOneUniqueUse ?
"user" :
"users") <<
": ";
3614 bool shouldPrintBrackets = numResults > 1;
3615 auto printOpResult = [&](
OpResult opResult) {
3616 if (shouldPrintBrackets)
3618 printValueUsers(opResult);
3619 if (shouldPrintBrackets)
3623 interleaveComma(op->
getResults(), printOpResult);
3627 void OperationPrinter::printUsersComment(
BlockArgument arg) {
3633 os <<
" is used by ";
3634 printValueUsers(arg);
3639 void OperationPrinter::printValueUsers(
Value value) {
3647 if (userSet.insert(user).second)
3648 printUserIDs(user, index);
3652 void OperationPrinter::printUserIDs(
Operation *user,
bool prefixComma) {
3657 printOperationID(user);
3660 [
this](
Value result) { printValueID(result); });
3664 void OperationPrinter::printCustomOrGenericOp(
Operation *op) {
3670 opInfo->printAssembly(op, *
this, defaultDialectStack.back());
3675 if (
auto opPrinter = dialect->getOperationPrinter(op)) {
3680 if (name.count(
'.') == 1)
3681 name.consume_front((defaultDialectStack.back() +
".").str());
3685 opPrinter(op, *
this);
3692 printGenericOp(op,
true);
3695 void OperationPrinter::printGenericOp(
Operation *op,
bool printOpName) {
3699 interleaveComma(op->
getOperands(), [&](
Value value) { printValueID(value); });
3706 [&](
Block *successor) { printBlockName(successor); });
3718 if (op->getNumRegions() != 0) {
3720 interleaveComma(op->getRegions(), [&](Region ®ion) {
3721 printRegion(region, /*printEntryBlockArgs=*/true,
3722 /*printBlockTerminators=*/true, /*printEmptyBlock=*/true);
3727 printOptionalAttrDict(op->getPropertiesStorage()
3728 ? llvm::to_vector(op->getDiscardableAttrs())
3731 // Print the type signature of the operation.
3733 printFunctionalType(op);
3736 void OperationPrinter::printBlockName(Block *block) {
3737 os << state.getSSANameState().getBlockInfo(block).name;
3740 void OperationPrinter::print(Block *block, bool printBlockArgs,
3741 bool printBlockTerminator) {
3742 // Print the block label and argument list if requested.
3743 if (printBlockArgs) {
3744 os.indent(currentIndent);
3745 printBlockName(block);
3747 // Print the argument list if non-empty.
3748 if (!block->args_empty()) {
3750 interleaveComma(block->getArguments(), [&](BlockArgument arg) {
3753 printType(arg.getType());
3754 // TODO: We should allow location aliases on block arguments.
3755 printTrailingLocation(arg.getLoc(), /*allowAlias*/ false);
3761 // Print out some context information about the predecessors of this block.
3762 if (!block->getParent()) {
3763 os << " // block is not in a region!";
3764 } else if (block->hasNoPredecessors()) {
3765 if (!block->isEntryBlock())
3766 os << " // no predecessors";
3767 } else if (auto *pred = block->getSinglePredecessor()) {
3769 printBlockName(pred);
3771 // We want to print the predecessors in a stable order, not in
3772 // whatever order the use-list is in, so gather and sort them.
3773 SmallVector<BlockInfo, 4> predIDs;
3774 for (auto *pred : block->getPredecessors())
3775 predIDs.push_back(state.getSSANameState().getBlockInfo(pred));
3776 llvm::sort(predIDs, [](BlockInfo lhs, BlockInfo rhs) {
3777 return lhs.ordering < rhs.ordering;
3780 os << " // " << predIDs.size() << " preds: ";
3782 interleaveComma(predIDs, [&](BlockInfo pred) { os << pred.name; });
3787 currentIndent += indentWidth;
3789 if (printerFlags.shouldPrintValueUsers()) {
3790 for (BlockArgument arg : block->getArguments()) {
3791 os.indent(currentIndent);
3792 printUsersComment(arg);
3796 bool hasTerminator =
3797 !block->empty() && block->back().hasTrait<OpTrait::IsTerminator>();
3798 auto range = llvm::make_range(
3800 std::prev(block->end(),
3801 (!hasTerminator || printBlockTerminator) ? 0 : 1));
3802 for (auto &op : range) {
3803 printFullOpWithIndentAndLoc(&op);
3806 currentIndent -= indentWidth;
3809 void OperationPrinter::printValueID(Value value, bool printResultNo,
3810 raw_ostream *streamOverride) const {
3811 state.getSSANameState().printValueID(value, printResultNo,
3812 streamOverride ? *streamOverride : os);
3815 void OperationPrinter::printOperationID(Operation *op,
3816 raw_ostream *streamOverride) const {
3817 state.getSSANameState().printOperationID(op, streamOverride ? *streamOverride
3821 void OperationPrinter::printSuccessor(Block *successor) {
3822 printBlockName(successor);
3825 void OperationPrinter::printSuccessorAndUseList(Block *successor,
3826 ValueRange succOperands) {
3827 printBlockName(successor);
3828 if (succOperands.empty())
3832 interleaveComma(succOperands,
3833 [this](Value operand) { printValueID(operand); });
3835 interleaveComma(succOperands,
3836 [this](Value operand) { printType(operand.getType()); });
3840 void OperationPrinter::printRegion(Region ®ion, bool printEntryBlockArgs,
3841 bool printBlockTerminators,
3842 bool printEmptyBlock) {
3843 if (printerFlags.shouldSkipRegions()) {
3847 os << "{" << newLine;
3848 if (!region.empty()) {
3849 auto restoreDefaultDialect =
3850 llvm::make_scope_exit([&]() { defaultDialectStack.pop_back(); });
3851 if (auto iface = dyn_cast<OpAsmOpInterface>(region.getParentOp()))
3852 defaultDialectStack.push_back(iface.getDefaultDialect());
3854 defaultDialectStack.push_back("");
3856 auto *entryBlock = ®ion.front();
3857 // Force printing the block header if printEmptyBlock is set and the block
3858 // is empty or if printEntryBlockArgs is set and there are arguments to
3860 bool shouldAlwaysPrintBlockHeader =
3861 (printEmptyBlock && entryBlock->empty()) ||
3862 (printEntryBlockArgs && entryBlock->getNumArguments() != 0);
3863 print(entryBlock, shouldAlwaysPrintBlockHeader, printBlockTerminators);
3864 for (auto &b : llvm::drop_begin(region.getBlocks(), 1))
3867 os.indent(currentIndent) << "}";
3870 void OperationPrinter::printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3871 ValueRange operands) {
3873 os << "<<NULL AFFINE MAP>>";
3876 AffineMap map = mapAttr.getValue();
3877 unsigned numDims = map.getNumDims();
3878 auto printValueName = [&](unsigned pos, bool isSymbol) {
3879 unsigned index = isSymbol ? numDims + pos : pos;
3880 assert(index < operands.size());
3883 printValueID(operands[index]);
3888 interleaveComma(map.getResults(), [&](AffineExpr expr) {
3889 printAffineExpr(expr, printValueName);
3893 void OperationPrinter::printAffineExprOfSSAIds(AffineExpr expr,
3894 ValueRange dimOperands,
3895 ValueRange symOperands) {
3896 auto printValueName = [&](unsigned pos, bool isSymbol) {
3898 return printValueID(dimOperands[pos]);
3900 printValueID(symOperands[pos]);
3903 printAffineExpr(expr, printValueName);
3906 //===----------------------------------------------------------------------===//
3907 // print and dump methods
3908 //===----------------------------------------------------------------------===//
3910 void Attribute::print(raw_ostream &os, bool elideType) const {
3912 os << "<<NULL ATTRIBUTE>>";
3916 AsmState state(getContext());
3917 print(os, state, elideType);
3919 void Attribute::print(raw_ostream &os, AsmState &state, bool elideType) const {
3920 using AttrTypeElision = AsmPrinter::Impl::AttrTypeElision;
3921 AsmPrinter::Impl(os, state.getImpl())
3922 .printAttribute(*this, elideType ? AttrTypeElision::Must
3923 : AttrTypeElision::Never);
3926 void Attribute::dump() const {
3927 print(llvm::errs());
3928 llvm::errs() << "\n";
3931 void Attribute::printStripped(raw_ostream &os, AsmState &state) const {
3933 os << "<<NULL ATTRIBUTE>>";
3937 AsmPrinter::Impl subPrinter(os, state.getImpl());
3938 if (succeeded(subPrinter.printAlias(*this)))
3941 auto &dialect = this->getDialect();
3942 uint64_t posPrior = os.tell();
3943 DialectAsmPrinter printer(subPrinter);
3944 dialect.printAttribute(*this, printer);
3945 if (posPrior != os.tell())
3948 // Fallback to printing with prefix if the above failed to write anything
3949 // to the output stream.
3952 void Attribute::printStripped(raw_ostream &os) const {
3954 os << "<<NULL ATTRIBUTE>>";
3958 AsmState state(getContext());
3959 printStripped(os, state);
3962 void Type::print(raw_ostream &os) const {
3964 os << "<<NULL TYPE>>";
3968 AsmState state(getContext());
3971 void Type::print(raw_ostream &os, AsmState &state) const {
3972 AsmPrinter::Impl(os, state.getImpl()).printType(*this);
3975 void Type::dump() const {
3976 print(llvm::errs());
3977 llvm::errs() << "\n";
3980 void AffineMap::dump() const {
3981 print(llvm::errs());
3982 llvm::errs() << "\n";
3985 void IntegerSet::dump() const {
3986 print(llvm::errs());
3987 llvm::errs() << "\n";
3990 void AffineExpr::print(raw_ostream &os) const {
3992 os << "<<NULL AFFINE EXPR>>";
3995 AsmState state(getContext());
3996 AsmPrinter::Impl(os, state.getImpl()).printAffineExpr(*this);
3999 void AffineExpr::dump() const {
4000 print(llvm::errs());
4001 llvm::errs() << "\n";
4004 void AffineMap::print(raw_ostream &os) const {
4006 os << "<<NULL AFFINE MAP>>";
4009 AsmState state(getContext());
4010 AsmPrinter::Impl(os, state.getImpl()).printAffineMap(*this);
4013 void IntegerSet::print(raw_ostream &os) const {
4014 AsmState state(getContext());
4015 AsmPrinter::Impl(os, state.getImpl()).printIntegerSet(*this);
4018 void Value::print(raw_ostream &os) const { print(os, OpPrintingFlags()); }
4019 void Value::print(raw_ostream &os, const OpPrintingFlags &flags) const {
4021 os << "<<NULL VALUE>>";
4025 if (auto *op = getDefiningOp())
4026 return op->print(os, flags);
4027 // TODO: Improve BlockArgument print'ing.
4029 os <<
"<block argument> of type '" << arg.
getType()
4034 os <<
"<<NULL VALUE>>";
4038 if (
auto *op = getDefiningOp())
4039 return op->
print(os, state);
4043 os <<
"<block argument> of type '" << arg.
getType()
4048 print(llvm::errs());
4049 llvm::errs() <<
"\n";
4057 state.getImpl().getSSANameState().printValueID(*
this,
true,
4080 if (
auto result = llvm::dyn_cast<OpResult>(*
this)) {
4083 op = llvm::cast<BlockArgument>(*this).getOwner()->
getParentOp();
4085 os <<
"<<UNKNOWN SSA VALUE>>";
4091 printAsOperand(os, state);
4101 OperationPrinter printer(os, state.getImpl());
4102 if (!getParent() && !state.getPrinterFlags().shouldUseLocalScope()) {
4103 state.getImpl().initializeAliases(
this);
4104 printer.printTopLevelOperation(
this);
4106 printer.printFullOpWithIndentAndLoc(
this);
4112 llvm::errs() <<
"\n";
4117 llvm::errs() <<
"\n";
4123 os <<
"<<UNLINKED BLOCK>>\n";
4134 OperationPrinter(os, state.getImpl()).print(
this);
4143 os <<
"<<UNLINKED BLOCK>>\n";
4147 printAsOperand(os, state);
4150 OperationPrinter printer(os, state.getImpl());
4151 printer.printBlockName(
this);
4166 if (dimensions.empty())
4169 if (dimensions.empty())
4179 <<
"Failed parsing dimension list.";
4190 <<
"Failed parsing dimension list.";
4192 if (shapeArr.empty()) {
4194 <<
"Failed parsing dimension list. Did you mean an empty list? It "
4195 "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::@1183::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.