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()) {
3467 if (charLimit.value() == 0)
3470 llvm::raw_string_ostream ss(resourceStr);
3474 if (resourceStr.size() > charLimit.value())
3478 valueFn = printResourceStr;
3482 if (!std::exchange(hadResource,
true)) {
3483 if (needResourceComma)
3484 os <<
"," << newLine;
3485 os <<
" " << dictName <<
"_resources: {" << newLine;
3488 if (!std::exchange(hadEntry,
true)) {
3490 os <<
"," << newLine;
3491 os <<
" " << name <<
": {" << newLine;
3493 os <<
"," << newLine;
3501 ResourceBuilder entryBuilder(printFn);
3502 provider.buildResources(op, providerArgs..., entryBuilder);
3504 needEntryComma |= hadEntry;
3506 os << newLine <<
" }";
3512 auto &dialectResources = state.getDialectResources();
3513 StringRef name = interface.getDialect()->getNamespace();
3514 auto it = dialectResources.find(interface.getDialect());
3515 if (it != dialectResources.end())
3516 processProvider(
"dialect", name, interface, it->second);
3518 processProvider(
"dialect", name, interface,
3522 os << newLine <<
" }";
3526 needEntryComma =
false;
3527 needResourceComma = hadResource;
3528 hadResource =
false;
3529 for (
const auto &printer : state.getResourcePrinters())
3530 processProvider(
"external", printer.getName(), printer);
3532 os << newLine <<
" }";
3540 void OperationPrinter::printRegionArgument(
BlockArgument arg,
3548 printOptionalAttrDict(argAttrs);
3550 printTrailingLocation(arg.
getLoc(),
false);
3553 void OperationPrinter::printFullOpWithIndentAndLoc(
Operation *op) {
3555 state.registerOperationLocation(op, newLine.curLine, currentIndent);
3557 os.indent(currentIndent);
3559 printTrailingLocation(op->
getLoc());
3561 printUsersComment(op);
3564 void OperationPrinter::printFullOp(
Operation *op) {
3566 auto printResultGroup = [&](
size_t resultNo,
size_t resultCount) {
3567 printValueID(op->
getResult(resultNo),
false);
3568 if (resultCount > 1)
3569 os <<
':' << resultCount;
3573 ArrayRef<int> resultGroups = state.getSSANameState().getOpResultGroups(op);
3574 if (!resultGroups.empty()) {
3577 interleaveComma(llvm::seq<int>(0, resultGroups.size() - 1), [&](
int i) {
3578 printResultGroup(resultGroups[i],
3579 resultGroups[i + 1] - resultGroups[i]);
3582 printResultGroup(resultGroups.back(), numResults - resultGroups.back());
3585 printResultGroup(0, numResults);
3591 printCustomOrGenericOp(op);
3594 void OperationPrinter::printUsersComment(
Operation *op) {
3598 printOperationID(op);
3599 }
else if (numResults && op->
use_empty()) {
3601 }
else if (numResults && !op->
use_empty()) {
3604 unsigned usedInNResults = 0;
3605 unsigned usedInNOperations = 0;
3608 if (userSet.insert(user).second) {
3609 ++usedInNOperations;
3610 usedInNResults += user->getNumResults();
3615 bool exactlyOneUniqueUse =
3616 usedInNResults <= 1 && usedInNOperations <= 1 && numResults == 1;
3617 os <<
" // " << (exactlyOneUniqueUse ?
"user" :
"users") <<
": ";
3618 bool shouldPrintBrackets = numResults > 1;
3619 auto printOpResult = [&](
OpResult opResult) {
3620 if (shouldPrintBrackets)
3622 printValueUsers(opResult);
3623 if (shouldPrintBrackets)
3627 interleaveComma(op->
getResults(), printOpResult);
3631 void OperationPrinter::printUsersComment(
BlockArgument arg) {
3637 os <<
" is used by ";
3638 printValueUsers(arg);
3643 void OperationPrinter::printValueUsers(
Value value) {
3651 if (userSet.insert(user).second)
3652 printUserIDs(user, index);
3656 void OperationPrinter::printUserIDs(
Operation *user,
bool prefixComma) {
3661 printOperationID(user);
3664 [
this](
Value result) { printValueID(result); });
3668 void OperationPrinter::printCustomOrGenericOp(
Operation *op) {
3674 opInfo->printAssembly(op, *
this, defaultDialectStack.back());
3679 if (
auto opPrinter = dialect->getOperationPrinter(op)) {
3684 if (name.count(
'.') == 1)
3685 name.consume_front((defaultDialectStack.back() +
".").str());
3689 opPrinter(op, *
this);
3696 printGenericOp(op,
true);
3699 void OperationPrinter::printGenericOp(
Operation *op,
bool printOpName) {
3703 interleaveComma(op->
getOperands(), [&](
Value value) { printValueID(value); });
3710 [&](
Block *successor) { printBlockName(successor); });
3722 if (op->getNumRegions() != 0) {
3724 interleaveComma(op->getRegions(), [&](Region ®ion) {
3725 printRegion(region, /*printEntryBlockArgs=*/true,
3726 /*printBlockTerminators=*/true, /*printEmptyBlock=*/true);
3731 printOptionalAttrDict(op->getPropertiesStorage()
3732 ? llvm::to_vector(op->getDiscardableAttrs())
3735 // Print the type signature of the operation.
3737 printFunctionalType(op);
3740 void OperationPrinter::printBlockName(Block *block) {
3741 os << state.getSSANameState().getBlockInfo(block).name;
3744 void OperationPrinter::print(Block *block, bool printBlockArgs,
3745 bool printBlockTerminator) {
3746 // Print the block label and argument list if requested.
3747 if (printBlockArgs) {
3748 os.indent(currentIndent);
3749 printBlockName(block);
3751 // Print the argument list if non-empty.
3752 if (!block->args_empty()) {
3754 interleaveComma(block->getArguments(), [&](BlockArgument arg) {
3757 printType(arg.getType());
3758 // TODO: We should allow location aliases on block arguments.
3759 printTrailingLocation(arg.getLoc(), /*allowAlias*/ false);
3765 // Print out some context information about the predecessors of this block.
3766 if (!block->getParent()) {
3767 os << " // block is not in a region!";
3768 } else if (block->hasNoPredecessors()) {
3769 if (!block->isEntryBlock())
3770 os << " // no predecessors";
3771 } else if (auto *pred = block->getSinglePredecessor()) {
3773 printBlockName(pred);
3775 // We want to print the predecessors in a stable order, not in
3776 // whatever order the use-list is in, so gather and sort them.
3777 SmallVector<BlockInfo, 4> predIDs;
3778 for (auto *pred : block->getPredecessors())
3779 predIDs.push_back(state.getSSANameState().getBlockInfo(pred));
3780 llvm::sort(predIDs, [](BlockInfo lhs, BlockInfo rhs) {
3781 return lhs.ordering < rhs.ordering;
3784 os << " // " << predIDs.size() << " preds: ";
3786 interleaveComma(predIDs, [&](BlockInfo pred) { os << pred.name; });
3791 currentIndent += indentWidth;
3793 if (printerFlags.shouldPrintValueUsers()) {
3794 for (BlockArgument arg : block->getArguments()) {
3795 os.indent(currentIndent);
3796 printUsersComment(arg);
3800 bool hasTerminator =
3801 !block->empty() && block->back().hasTrait<OpTrait::IsTerminator>();
3802 auto range = llvm::make_range(
3804 std::prev(block->end(),
3805 (!hasTerminator || printBlockTerminator) ? 0 : 1));
3806 for (auto &op : range) {
3807 printFullOpWithIndentAndLoc(&op);
3810 currentIndent -= indentWidth;
3813 void OperationPrinter::printValueID(Value value, bool printResultNo,
3814 raw_ostream *streamOverride) const {
3815 state.getSSANameState().printValueID(value, printResultNo,
3816 streamOverride ? *streamOverride : os);
3819 void OperationPrinter::printOperationID(Operation *op,
3820 raw_ostream *streamOverride) const {
3821 state.getSSANameState().printOperationID(op, streamOverride ? *streamOverride
3825 void OperationPrinter::printSuccessor(Block *successor) {
3826 printBlockName(successor);
3829 void OperationPrinter::printSuccessorAndUseList(Block *successor,
3830 ValueRange succOperands) {
3831 printBlockName(successor);
3832 if (succOperands.empty())
3836 interleaveComma(succOperands,
3837 [this](Value operand) { printValueID(operand); });
3839 interleaveComma(succOperands,
3840 [this](Value operand) { printType(operand.getType()); });
3844 void OperationPrinter::printRegion(Region ®ion, bool printEntryBlockArgs,
3845 bool printBlockTerminators,
3846 bool printEmptyBlock) {
3847 if (printerFlags.shouldSkipRegions()) {
3851 os << "{" << newLine;
3852 if (!region.empty()) {
3853 auto restoreDefaultDialect =
3854 llvm::make_scope_exit([&]() { defaultDialectStack.pop_back(); });
3855 if (auto iface = dyn_cast<OpAsmOpInterface>(region.getParentOp()))
3856 defaultDialectStack.push_back(iface.getDefaultDialect());
3858 defaultDialectStack.push_back("");
3860 auto *entryBlock = ®ion.front();
3861 // Force printing the block header if printEmptyBlock is set and the block
3862 // is empty or if printEntryBlockArgs is set and there are arguments to
3864 bool shouldAlwaysPrintBlockHeader =
3865 (printEmptyBlock && entryBlock->empty()) ||
3866 (printEntryBlockArgs && entryBlock->getNumArguments() != 0);
3867 print(entryBlock, shouldAlwaysPrintBlockHeader, printBlockTerminators);
3868 for (auto &b : llvm::drop_begin(region.getBlocks(), 1))
3871 os.indent(currentIndent) << "}";
3874 void OperationPrinter::printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3875 ValueRange operands) {
3877 os << "<<NULL AFFINE MAP>>";
3880 AffineMap map = mapAttr.getValue();
3881 unsigned numDims = map.getNumDims();
3882 auto printValueName = [&](unsigned pos, bool isSymbol) {
3883 unsigned index = isSymbol ? numDims + pos : pos;
3884 assert(index < operands.size());
3887 printValueID(operands[index]);
3892 interleaveComma(map.getResults(), [&](AffineExpr expr) {
3893 printAffineExpr(expr, printValueName);
3897 void OperationPrinter::printAffineExprOfSSAIds(AffineExpr expr,
3898 ValueRange dimOperands,
3899 ValueRange symOperands) {
3900 auto printValueName = [&](unsigned pos, bool isSymbol) {
3902 return printValueID(dimOperands[pos]);
3904 printValueID(symOperands[pos]);
3907 printAffineExpr(expr, printValueName);
3910 //===----------------------------------------------------------------------===//
3911 // print and dump methods
3912 //===----------------------------------------------------------------------===//
3914 void Attribute::print(raw_ostream &os, bool elideType) const {
3916 os << "<<NULL ATTRIBUTE>>";
3920 AsmState state(getContext());
3921 print(os, state, elideType);
3923 void Attribute::print(raw_ostream &os, AsmState &state, bool elideType) const {
3924 using AttrTypeElision = AsmPrinter::Impl::AttrTypeElision;
3925 AsmPrinter::Impl(os, state.getImpl())
3926 .printAttribute(*this, elideType ? AttrTypeElision::Must
3927 : AttrTypeElision::Never);
3930 void Attribute::dump() const {
3931 print(llvm::errs());
3932 llvm::errs() << "\n";
3935 void Attribute::printStripped(raw_ostream &os, AsmState &state) const {
3937 os << "<<NULL ATTRIBUTE>>";
3941 AsmPrinter::Impl subPrinter(os, state.getImpl());
3942 if (succeeded(subPrinter.printAlias(*this)))
3945 auto &dialect = this->getDialect();
3946 uint64_t posPrior = os.tell();
3947 DialectAsmPrinter printer(subPrinter);
3948 dialect.printAttribute(*this, printer);
3949 if (posPrior != os.tell())
3952 // Fallback to printing with prefix if the above failed to write anything
3953 // to the output stream.
3956 void Attribute::printStripped(raw_ostream &os) const {
3958 os << "<<NULL ATTRIBUTE>>";
3962 AsmState state(getContext());
3963 printStripped(os, state);
3966 void Type::print(raw_ostream &os) const {
3968 os << "<<NULL TYPE>>";
3972 AsmState state(getContext());
3975 void Type::print(raw_ostream &os, AsmState &state) const {
3976 AsmPrinter::Impl(os, state.getImpl()).printType(*this);
3979 void Type::dump() const {
3980 print(llvm::errs());
3981 llvm::errs() << "\n";
3984 void AffineMap::dump() const {
3985 print(llvm::errs());
3986 llvm::errs() << "\n";
3989 void IntegerSet::dump() const {
3990 print(llvm::errs());
3991 llvm::errs() << "\n";
3994 void AffineExpr::print(raw_ostream &os) const {
3996 os << "<<NULL AFFINE EXPR>>";
3999 AsmState state(getContext());
4000 AsmPrinter::Impl(os, state.getImpl()).printAffineExpr(*this);
4003 void AffineExpr::dump() const {
4004 print(llvm::errs());
4005 llvm::errs() << "\n";
4008 void AffineMap::print(raw_ostream &os) const {
4010 os << "<<NULL AFFINE MAP>>";
4013 AsmState state(getContext());
4014 AsmPrinter::Impl(os, state.getImpl()).printAffineMap(*this);
4017 void IntegerSet::print(raw_ostream &os) const {
4018 AsmState state(getContext());
4019 AsmPrinter::Impl(os, state.getImpl()).printIntegerSet(*this);
4022 void Value::print(raw_ostream &os) const { print(os, OpPrintingFlags()); }
4023 void Value::print(raw_ostream &os, const OpPrintingFlags &flags) const {
4025 os << "<<NULL VALUE>>";
4029 if (auto *op = getDefiningOp())
4030 return op->print(os, flags);
4031 // TODO: Improve BlockArgument print'ing.
4033 os <<
"<block argument> of type '" << arg.
getType()
4038 os <<
"<<NULL VALUE>>";
4042 if (
auto *op = getDefiningOp())
4043 return op->
print(os, state);
4047 os <<
"<block argument> of type '" << arg.
getType()
4052 print(llvm::errs());
4053 llvm::errs() <<
"\n";
4061 state.getImpl().getSSANameState().printValueID(*
this,
true,
4084 if (
auto result = llvm::dyn_cast<OpResult>(*
this)) {
4087 op = llvm::cast<BlockArgument>(*this).getOwner()->
getParentOp();
4089 os <<
"<<UNKNOWN SSA VALUE>>";
4095 printAsOperand(os, state);
4105 OperationPrinter printer(os, state.getImpl());
4106 if (!getParent() && !state.getPrinterFlags().shouldUseLocalScope()) {
4107 state.getImpl().initializeAliases(
this);
4108 printer.printTopLevelOperation(
this);
4110 printer.printFullOpWithIndentAndLoc(
this);
4116 llvm::errs() <<
"\n";
4121 llvm::errs() <<
"\n";
4127 os <<
"<<UNLINKED BLOCK>>\n";
4138 OperationPrinter(os, state.getImpl()).print(
this);
4147 os <<
"<<UNLINKED BLOCK>>\n";
4151 printAsOperand(os, state);
4154 OperationPrinter printer(os, state.getImpl());
4155 printer.printBlockName(
this);
4170 if (dimensions.empty())
4173 if (dimensions.empty())
4183 <<
"Failed parsing dimension list.";
4194 <<
"Failed parsing dimension list.";
4196 if (shapeArr.empty()) {
4198 <<
"Failed parsing dimension list. Did you mean an empty list? It "
4199 "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::@1197::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.