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/StringExtras.h"
40 #include "llvm/ADT/StringSet.h"
41 #include "llvm/ADT/TypeSwitch.h"
42 #include "llvm/Support/CommandLine.h"
43 #include "llvm/Support/DebugLog.h"
44 #include "llvm/Support/Endian.h"
45 #include "llvm/Support/ManagedStatic.h"
46 #include "llvm/Support/Regex.h"
47 #include "llvm/Support/SaveAndRestore.h"
48 #include "llvm/Support/Threading.h"
49 #include "llvm/Support/raw_ostream.h"
50 #include <type_traits>
58 #define DEBUG_TYPE "mlir-asm-printer"
79 [&]() {
return parseType(result.emplace_back()); });
95 auto &os = getStream();
99 *this << (operand ? operand.getType() : Type());
115 *this << (result ? result.getType() : Type());
127 #include "mlir/IR/OpAsmAttrInterface.cpp.inc"
128 #include "mlir/IR/OpAsmOpInterface.cpp.inc"
129 #include "mlir/IR/OpAsmTypeInterface.cpp.inc"
133 return entry.
emitError() <<
"unknown 'resource' key '" << entry.
getKey()
134 <<
"' for dialect '" << getDialect()->getNamespace()
146 struct AsmPrinterOptions {
147 llvm::cl::opt<int64_t> printElementsAttrWithHexIfLarger{
148 "mlir-print-elementsattrs-with-hex-if-larger",
150 "Print DenseElementsAttrs with a hex string that have "
151 "more elements than the given upper limit (use -1 to disable)")};
153 llvm::cl::opt<unsigned> elideElementsAttrIfLarger{
154 "mlir-elide-elementsattrs-if-larger",
155 llvm::cl::desc(
"Elide ElementsAttrs with \"...\" that have "
156 "more elements than the given upper limit")};
158 llvm::cl::opt<unsigned> elideResourceStringsIfLarger{
159 "mlir-elide-resource-strings-if-larger",
161 "Elide printing value of resources if string is too long in chars.")};
163 llvm::cl::opt<bool> printDebugInfoOpt{
164 "mlir-print-debuginfo", llvm::cl::init(
false),
165 llvm::cl::desc(
"Print debug info in MLIR output")};
167 llvm::cl::opt<bool> printPrettyDebugInfoOpt{
168 "mlir-pretty-debuginfo", llvm::cl::init(
false),
169 llvm::cl::desc(
"Print pretty debug info in MLIR output")};
173 llvm::cl::opt<bool> printGenericOpFormOpt{
174 "mlir-print-op-generic", llvm::cl::init(
false),
175 llvm::cl::desc(
"Print the generic op form"), llvm::cl::Hidden};
177 llvm::cl::opt<bool> assumeVerifiedOpt{
178 "mlir-print-assume-verified", llvm::cl::init(
false),
179 llvm::cl::desc(
"Skip op verification when using custom printers"),
182 llvm::cl::opt<bool> printLocalScopeOpt{
183 "mlir-print-local-scope", llvm::cl::init(
false),
184 llvm::cl::desc(
"Print with local scope and inline information (eliding "
185 "aliases for attributes, types, and locations)")};
187 llvm::cl::opt<bool> skipRegionsOpt{
188 "mlir-print-skip-regions", llvm::cl::init(
false),
189 llvm::cl::desc(
"Skip regions when printing ops.")};
191 llvm::cl::opt<bool> printValueUsers{
192 "mlir-print-value-users", llvm::cl::init(
false),
194 "Print users of operation results and block arguments as a comment")};
196 llvm::cl::opt<bool> printUniqueSSAIDs{
197 "mlir-print-unique-ssa-ids", llvm::cl::init(
false),
198 llvm::cl::desc(
"Print unique SSA ID numbers for values, block arguments "
199 "and naming conflicts across all regions")};
201 llvm::cl::opt<bool> useNameLocAsPrefix{
202 "mlir-use-nameloc-as-prefix", llvm::cl::init(
false),
203 llvm::cl::desc(
"Print SSA IDs using NameLocs as prefixes")};
207 static llvm::ManagedStatic<AsmPrinterOptions>
clOptions;
218 : printDebugInfoFlag(false), printDebugInfoPrettyFormFlag(false),
219 printGenericOpFormFlag(false), skipRegionsFlag(false),
220 assumeVerifiedFlag(false), printLocalScope(false),
221 printValueUsersFlag(false), printUniqueSSAIDsFlag(false),
222 useNameLocAsPrefix(false) {
226 if (
clOptions->elideElementsAttrIfLarger.getNumOccurrences())
227 elementsAttrElementLimit =
clOptions->elideElementsAttrIfLarger;
228 if (
clOptions->printElementsAttrWithHexIfLarger.getNumOccurrences())
229 elementsAttrHexElementLimit =
230 clOptions->printElementsAttrWithHexIfLarger.getValue();
231 if (
clOptions->elideResourceStringsIfLarger.getNumOccurrences())
232 resourceStringCharLimit =
clOptions->elideResourceStringsIfLarger;
233 printDebugInfoFlag =
clOptions->printDebugInfoOpt;
234 printDebugInfoPrettyFormFlag =
clOptions->printPrettyDebugInfoOpt;
235 printGenericOpFormFlag =
clOptions->printGenericOpFormOpt;
236 assumeVerifiedFlag =
clOptions->assumeVerifiedOpt;
237 printLocalScope =
clOptions->printLocalScopeOpt;
238 skipRegionsFlag =
clOptions->skipRegionsOpt;
239 printValueUsersFlag =
clOptions->printValueUsers;
240 printUniqueSSAIDsFlag =
clOptions->printUniqueSSAIDs;
241 useNameLocAsPrefix =
clOptions->useNameLocAsPrefix;
250 elementsAttrElementLimit = largeElementLimit;
256 elementsAttrHexElementLimit = largeElementLimit;
262 resourceStringCharLimit = largeResourceLimit;
270 printDebugInfoFlag = enable;
271 printDebugInfoPrettyFormFlag = prettyForm;
277 printGenericOpFormFlag = enable;
283 skipRegionsFlag = skip;
289 assumeVerifiedFlag = enable;
297 printLocalScope = enable;
303 printValueUsersFlag = enable;
310 printUniqueSSAIDsFlag = enable;
316 return elementsAttrElementLimit &&
317 *elementsAttrElementLimit < int64_t(attr.getNumElements()) &&
318 !llvm::isa<SplatElementsAttr>(attr);
324 return (elementsAttrHexElementLimit != -1) &&
325 (elementsAttrHexElementLimit < int64_t(attr.getNumElements())) &&
326 !llvm::isa<SplatElementsAttr>(attr);
330 useNameLocAsPrefix = enable;
336 return elementsAttrElementLimit;
341 return elementsAttrHexElementLimit;
346 return resourceStringCharLimit;
351 return printDebugInfoFlag;
356 return printDebugInfoPrettyFormFlag;
361 return printGenericOpFormFlag;
369 return assumeVerifiedFlag;
377 return printValueUsersFlag;
387 return useNameLocAsPrefix;
398 struct NewLineCounter {
399 unsigned curLine = 1;
402 static raw_ostream &
operator<<(raw_ostream &os, NewLineCounter &newLine) {
421 template <
typename Container,
typename UnaryFunctor>
423 llvm::interleaveComma(c,
os, eachFn);
470 function_ref<
void(
unsigned,
bool)> printValueName =
nullptr);
483 bool withKeyword =
false);
486 bool isTopLevel =
false);
522 function_ref<
void(
unsigned,
bool)> printValueName =
nullptr);
546 SymbolAlias(StringRef name, uint32_t suffixIndex,
bool isType,
548 : name(name), suffixIndex(suffixIndex), isType(isType),
549 isDeferrable(isDeferrable) {}
552 void print(raw_ostream &os)
const {
553 os << (isType ?
"!" :
"#") << name;
555 if (isdigit(name.back()))
562 bool isTypeAlias()
const {
return isType; }
565 bool canBeDeferred()
const {
return isDeferrable; }
571 uint32_t suffixIndex : 30;
575 bool isDeferrable : 1;
579 bool isPrinted =
false;
585 class AliasInitializer {
589 llvm::BumpPtrAllocator &aliasAllocator)
590 : interfaces(interfaces), aliasAllocator(aliasAllocator),
591 aliasOS(aliasBuffer) {}
594 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias);
602 std::pair<size_t, size_t>
visit(
Attribute attr,
bool canBeDeferred =
false,
603 bool elideType =
false) {
604 return visitImpl(attr, aliases, canBeDeferred, elideType);
611 std::pair<size_t, size_t>
visit(
Type type,
bool canBeDeferred =
false) {
612 return visitImpl(type, aliases, canBeDeferred);
616 struct InProgressAliasInfo {
617 InProgressAliasInfo()
618 : aliasDepth(0), isType(false), canBeDeferred(false) {}
619 InProgressAliasInfo(StringRef alias)
620 : alias(alias), aliasDepth(1), isType(false), canBeDeferred(false) {}
622 bool operator<(
const InProgressAliasInfo &rhs)
const {
624 if (aliasDepth != rhs.aliasDepth)
625 return aliasDepth < rhs.aliasDepth;
626 if (isType != rhs.isType)
628 return alias < rhs.alias;
633 std::optional<StringRef> alias;
636 unsigned aliasDepth : 30;
640 bool canBeDeferred : 1;
650 template <
typename T,
typename... PrintArgs>
651 std::pair<size_t, size_t>
653 llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
654 bool canBeDeferred, PrintArgs &&...
printArgs);
657 void markAliasNonDeferrable(
size_t aliasIndex);
661 template <
typename T>
662 void generateAlias(T symbol, InProgressAliasInfo &alias,
bool canBeDeferred);
667 uniqueAliasNameIndex(StringRef alias, llvm::StringMap<unsigned> &nameCounts,
672 static void initializeAliases(
673 llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
674 llvm::MapVector<const void *, SymbolAlias> &symbolToAlias);
680 llvm::BumpPtrAllocator &aliasAllocator;
683 llvm::MapVector<const void *, InProgressAliasInfo> aliases;
687 llvm::raw_svector_ostream aliasOS;
695 class DummyAliasOperationPrinter :
private OpAsmPrinter {
697 explicit DummyAliasOperationPrinter(
const OpPrintingFlags &printerFlags,
698 AliasInitializer &initializer)
699 : printerFlags(printerFlags), initializer(initializer) {}
703 void printCustomOrGenericOp(
Operation *op)
override {
705 if (printerFlags.shouldPrintDebugInfo())
706 initializer.visit(op->
getLoc(),
true);
709 if (!printerFlags.shouldPrintGenericOpForm()) {
720 void printGenericOp(
Operation *op,
bool printOpName =
true)
override {
722 if (!printerFlags.shouldSkipRegions()) {
736 printAttribute(attr.getValue());
742 void print(
Block *block,
bool printBlockArgs =
true,
743 bool printBlockTerminator =
true) {
746 if (printBlockArgs) {
751 if (printerFlags.shouldPrintDebugInfo())
753 initializer.visit(arg.getLoc(),
false);
761 auto range = llvm::make_range(
763 std::prev(block->
end(),
764 (!hasTerminator || printBlockTerminator) ? 0 : 1));
766 printCustomOrGenericOp(&op);
771 bool printBlockTerminators,
772 bool printEmptyBlock =
false)
override {
775 if (printerFlags.shouldSkipRegions()) {
780 auto *entryBlock = ®ion.
front();
781 print(entryBlock, printEntryBlockArgs, printBlockTerminators);
782 for (
Block &b : llvm::drop_begin(region, 1))
787 bool omitType)
override {
790 if (printerFlags.shouldPrintDebugInfo())
792 initializer.visit(arg.
getLoc(),
false);
796 void printType(
Type type)
override { initializer.visit(type); }
799 void printAttribute(
Attribute attr)
override { initializer.visit(attr); }
800 void printAttributeWithoutType(
Attribute attr)
override {
801 printAttribute(attr);
807 LogicalResult printAlias(
Attribute attr)
override {
808 initializer.visit(attr);
811 LogicalResult printAlias(
Type type)
override {
812 initializer.visit(type);
817 void printOptionalLocationSpecifier(
Location loc)
override {
827 if (elidedAttrs.empty()) {
829 printAttribute(attr.getValue());
832 llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
835 if (!elidedAttrsSet.contains(attr.getName().strref()))
836 printAttribute(attr.getValue());
838 void printOptionalAttrDictWithKeyword(
841 printOptionalAttrDict(attrs, elidedAttrs);
846 raw_ostream &getStream()
const override {
return os; }
850 void printFloat(
const APFloat &)
override {}
851 void printAffineMapOfSSAIds(AffineMapAttr,
ValueRange)
override {}
854 void increaseIndent()
override {}
855 void decreaseIndent()
override {}
856 void printOperand(
Value)
override {}
857 void printOperand(
Value, raw_ostream &os)
override {
866 void printSymbolName(StringRef)
override {}
867 void printSuccessor(
Block *)
override {}
875 AliasInitializer &initializer;
878 mutable llvm::raw_null_ostream os;
883 explicit DummyAliasDialectAsmPrinter(AliasInitializer &initializer,
886 : initializer(initializer), canBeDeferred(canBeDeferred),
887 childIndices(childIndices) {}
892 template <
typename T,
typename... PrintArgs>
893 size_t printAndVisitNestedAliases(T value, PrintArgs &&...
printArgs) {
894 printAndVisitNestedAliasesImpl(value,
printArgs...);
895 return maxAliasDepth;
901 void printAndVisitNestedAliasesImpl(
Attribute attr,
bool elideType) {
902 if (!isa<BuiltinDialect>(attr.
getDialect())) {
906 }
else if (llvm::isa<AffineMapAttr, DenseArrayAttr, FloatAttr, IntegerAttr,
907 IntegerSetAttr, UnitAttr>(attr)) {
909 }
else if (
auto distinctAttr = dyn_cast<DistinctAttr>(attr)) {
910 printAttribute(distinctAttr.getReferencedAttr());
911 }
else if (
auto dictAttr = dyn_cast<DictionaryAttr>(attr)) {
913 printAttribute(nestedAttr.getName());
914 printAttribute(nestedAttr.getValue());
916 }
else if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr)) {
917 for (
Attribute nestedAttr : arrayAttr.getValue())
918 printAttribute(nestedAttr);
919 }
else if (
auto typeAttr = dyn_cast<TypeAttr>(attr)) {
921 }
else if (
auto locAttr = dyn_cast<OpaqueLoc>(attr)) {
922 printAttribute(locAttr.getFallbackLocation());
923 }
else if (
auto locAttr = dyn_cast<NameLoc>(attr)) {
924 if (!isa<UnknownLoc>(locAttr.getChildLoc()))
925 printAttribute(locAttr.getChildLoc());
926 }
else if (
auto locAttr = dyn_cast<CallSiteLoc>(attr)) {
927 printAttribute(locAttr.getCallee());
928 printAttribute(locAttr.getCaller());
929 }
else if (
auto locAttr = dyn_cast<FusedLoc>(attr)) {
930 if (
Attribute metadata = locAttr.getMetadata())
931 printAttribute(metadata);
932 for (
Location nestedLoc : locAttr.getLocations())
933 printAttribute(nestedLoc);
938 if (
auto typedAttr = llvm::dyn_cast<TypedAttr>(attr)) {
939 Type attrType = typedAttr.getType();
940 if (!llvm::isa<NoneType>(attrType))
945 void printAndVisitNestedAliasesImpl(
Type type) {
950 if (
auto memrefTy = llvm::dyn_cast<MemRefType>(type)) {
952 MemRefLayoutAttrInterface layout = memrefTy.getLayout();
953 if (!llvm::isa<AffineMapAttr>(layout) || !layout.isIdentity())
954 printAttribute(memrefTy.getLayout());
955 if (memrefTy.getMemorySpace())
956 printAttribute(memrefTy.getMemorySpace());
961 auto visitFn = [&](
auto element) {
963 (void)printAlias(element);
970 recordAliasResult(initializer.visit(type, canBeDeferred));
974 void printAttribute(
Attribute attr)
override {
975 recordAliasResult(initializer.visit(attr, canBeDeferred));
977 void printAttributeWithoutType(
Attribute attr)
override {
979 initializer.visit(attr, canBeDeferred,
true));
985 LogicalResult printAlias(
Attribute attr)
override {
986 printAttribute(attr);
989 LogicalResult printAlias(
Type type)
override {
995 void recordAliasResult(std::pair<size_t, size_t> aliasDepthAndIndex) {
996 childIndices.push_back(aliasDepthAndIndex.second);
997 if (aliasDepthAndIndex.first > maxAliasDepth)
998 maxAliasDepth = aliasDepthAndIndex.first;
1003 raw_ostream &getStream()
const override {
return os; }
1007 void printFloat(
const APFloat &)
override {}
1010 void printSymbolName(StringRef)
override {}
1013 LogicalResult pushCyclicPrinting(
const void *opaquePointer)
override {
1014 return success(cyclicPrintingStack.insert(opaquePointer));
1017 void popCyclicPrinting()
override { cyclicPrintingStack.pop_back(); }
1024 AliasInitializer &initializer;
1033 size_t maxAliasDepth = 0;
1036 mutable llvm::raw_null_ostream os;
1044 StringRef allowedPunctChars =
"$._-") {
1045 assert(!name.empty() &&
"Shouldn't have an empty name here");
1047 auto validChar = [&](
char ch) {
1048 return llvm::isAlnum(ch) || allowedPunctChars.contains(ch);
1051 auto copyNameToBuffer = [&] {
1052 for (
char ch : name) {
1054 buffer.push_back(ch);
1056 buffer.push_back(
'_');
1058 buffer.append(llvm::utohexstr((
unsigned char)ch));
1065 if (isdigit(name[0]) || (!validChar(name[0]) && name[0] !=
' ')) {
1066 buffer.push_back(
'_');
1072 for (
char ch : name) {
1073 if (!validChar(ch)) {
1083 unsigned AliasInitializer::uniqueAliasNameIndex(
1084 StringRef alias, llvm::StringMap<unsigned> &nameCounts,
1086 if (!usedAliases.count(alias)) {
1087 usedAliases.insert(alias);
1094 if (isdigit(alias.back()))
1095 probeAlias.push_back(
'_');
1097 if (nameCounts[probeAlias] == 0)
1098 nameCounts[probeAlias] = 1;
1102 unsigned nameIndex = nameCounts[probeAlias]++;
1103 probeAlias += llvm::utostr(nameIndex);
1104 if (!usedAliases.count(probeAlias)) {
1105 usedAliases.insert(probeAlias);
1109 probeAlias.resize(alias.size() + isdigit(alias.back()) ? 1 : 0);
1115 void AliasInitializer::initializeAliases(
1116 llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
1117 llvm::MapVector<const void *, SymbolAlias> &symbolToAlias) {
1119 unprocessedAliases = visitedSymbols.takeVector();
1120 llvm::stable_sort(unprocessedAliases, llvm::less_second());
1124 llvm::BumpPtrAllocator usedAliasAllocator;
1127 llvm::StringMap<unsigned> nameCounts;
1128 for (
auto &[symbol, aliasInfo] : unprocessedAliases) {
1129 if (!aliasInfo.alias)
1131 StringRef alias = *aliasInfo.alias;
1132 unsigned nameIndex = uniqueAliasNameIndex(alias, nameCounts, usedAliases);
1133 symbolToAlias.insert(
1134 {symbol, SymbolAlias(alias, nameIndex, aliasInfo.isType,
1135 aliasInfo.canBeDeferred)});
1139 void AliasInitializer::initialize(
1141 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias) {
1145 DummyAliasOperationPrinter aliasPrinter(printerFlags, *
this);
1146 aliasPrinter.printCustomOrGenericOp(op);
1149 initializeAliases(aliases, attrTypeToAlias);
1152 template <
typename T,
typename... PrintArgs>
1153 std::pair<size_t, size_t> AliasInitializer::visitImpl(
1154 T value, llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
1155 bool canBeDeferred, PrintArgs &&...
printArgs) {
1156 auto [it, inserted] = aliases.try_emplace(value.getAsOpaquePointer());
1157 size_t aliasIndex = std::distance(aliases.begin(), it);
1161 markAliasNonDeferrable(aliasIndex);
1162 return {
static_cast<size_t>(it->second.aliasDepth), aliasIndex};
1166 generateAlias(value, it->second, canBeDeferred);
1167 it->second.isType = std::is_base_of_v<Type, T>;
1168 it->second.canBeDeferred = canBeDeferred;
1172 DummyAliasDialectAsmPrinter printer(*
this, canBeDeferred, childAliases);
1173 size_t maxAliasDepth =
1174 printer.printAndVisitNestedAliases(value,
printArgs...);
1177 it = std::next(aliases.begin(), aliasIndex);
1180 it->second.childIndices = std::move(childAliases);
1182 it->second.aliasDepth = maxAliasDepth + 1;
1185 return {(size_t)it->second.aliasDepth, aliasIndex};
1188 void AliasInitializer::markAliasNonDeferrable(
size_t aliasIndex) {
1189 auto *it = std::next(aliases.begin(), aliasIndex);
1193 if (!it->second.canBeDeferred)
1196 it->second.canBeDeferred =
false;
1199 for (
size_t childIndex : it->second.childIndices)
1200 markAliasNonDeferrable(childIndex);
1203 template <
typename T>
1204 void AliasInitializer::generateAlias(T symbol, InProgressAliasInfo &alias,
1205 bool canBeDeferred) {
1210 using InterfaceT = std::conditional_t<std::is_base_of_v<Attribute, T>,
1211 OpAsmAttrInterface, OpAsmTypeInterface>;
1212 if (
auto symbolInterface = dyn_cast<InterfaceT>(symbol)) {
1213 symbolInterfaceResult = symbolInterface.getAlias(aliasOS);
1215 nameBuffer = std::move(aliasBuffer);
1216 assert(!nameBuffer.empty() &&
"expected valid alias name");
1220 if (symbolInterfaceResult != OpAsmDialectInterface::AliasResult::FinalAlias) {
1221 for (
const auto &interface : interfaces) {
1223 interface.getAlias(symbol, aliasOS);
1226 nameBuffer = std::move(aliasBuffer);
1227 assert(!nameBuffer.empty() &&
"expected valid alias name");
1228 if (result == OpAsmDialectInterface::AliasResult::FinalAlias)
1233 if (nameBuffer.empty())
1239 name = name.copy(aliasAllocator);
1240 alias = InProgressAliasInfo(name);
1258 LogicalResult getAlias(
Attribute attr, raw_ostream &os)
const;
1262 LogicalResult getAlias(
Type ty, raw_ostream &os)
const;
1266 void printNonDeferredAliases(
AsmPrinter::Impl &p, NewLineCounter &newLine) {
1267 printAliases(p, newLine,
false);
1272 printAliases(p, newLine,
true);
1282 llvm::MapVector<const void *, SymbolAlias> attrTypeToAlias;
1285 llvm::BumpPtrAllocator aliasAllocator;
1289 void AliasState::initialize(
1292 AliasInitializer initializer(interfaces, aliasAllocator);
1293 initializer.initialize(op, printerFlags, attrTypeToAlias);
1296 LogicalResult AliasState::getAlias(
Attribute attr, raw_ostream &os)
const {
1298 if (it == attrTypeToAlias.end())
1300 it->second.print(os);
1304 LogicalResult AliasState::getAlias(
Type ty, raw_ostream &os)
const {
1306 if (it == attrTypeToAlias.end())
1308 if (!it->second.isPrinted)
1311 it->second.print(os);
1315 void AliasState::printAliases(
AsmPrinter::Impl &p, NewLineCounter &newLine,
1317 auto filterFn = [=](
const auto &aliasIt) {
1318 return aliasIt.second.canBeDeferred() == isDeferred;
1320 for (
auto &[opaqueSymbol, alias] :
1321 llvm::make_filter_range(attrTypeToAlias, filterFn)) {
1325 if (alias.isTypeAlias()) {
1328 alias.isPrinted =
true;
1355 class SSANameState {
1358 enum :
unsigned { NameSentinel = ~0U };
1361 SSANameState() =
default;
1366 void printValueID(
Value value,
bool printResultNo, raw_ostream &stream)
const;
1369 void printOperationID(
Operation *op, raw_ostream &stream)
const;
1376 BlockInfo getBlockInfo(
Block *block);
1385 void numberValuesInRegion(
Region ®ion);
1386 void numberValuesInBlock(
Block &block);
1393 void getResultIDAndNumber(
OpResult result,
Value &lookupValue,
1394 std::optional<int> &lookupResultNo)
const;
1397 void setValueName(
Value value, StringRef name);
1401 StringRef uniqueValueName(StringRef name);
1424 llvm::ScopedHashTable<StringRef, char> usedNames;
1425 llvm::BumpPtrAllocator usedNameAllocator;
1428 unsigned nextValueID = 0;
1430 unsigned nextArgumentID = 0;
1432 unsigned nextConflictID = 0;
1441 : printerFlags(printerFlags) {
1442 llvm::SaveAndRestore valueIDSaver(nextValueID);
1443 llvm::SaveAndRestore argumentIDSaver(nextArgumentID);
1444 llvm::SaveAndRestore conflictIDSaver(nextConflictID);
1449 using UsedNamesScopeTy = llvm::ScopedHashTable<StringRef, char>::ScopeTy;
1450 using NamingContext =
1451 std::tuple<Region *, unsigned, unsigned, unsigned, UsedNamesScopeTy *>;
1454 llvm::BumpPtrAllocator allocator;
1457 auto *topLevelNamesScope =
1458 new (allocator.Allocate<UsedNamesScopeTy>()) UsedNamesScopeTy(usedNames);
1462 nameContext.push_back(std::make_tuple(®ion, nextValueID, nextArgumentID,
1463 nextConflictID, topLevelNamesScope));
1465 numberValuesInOp(*op);
1467 while (!nameContext.empty()) {
1469 UsedNamesScopeTy *parentScope;
1473 std::tie(region, std::ignore, std::ignore, std::ignore, parentScope) =
1474 nameContext.pop_back_val();
1476 std::tie(region, nextValueID, nextArgumentID, nextConflictID,
1477 parentScope) = nameContext.pop_back_val();
1481 while (usedNames.getCurScope() != parentScope) {
1482 usedNames.getCurScope()->~UsedNamesScopeTy();
1483 assert((usedNames.getCurScope() !=
nullptr || parentScope ==
nullptr) &&
1484 "top level parentScope must be a nullptr");
1488 auto *curNamesScope =
new (allocator.Allocate<UsedNamesScopeTy>())
1489 UsedNamesScopeTy(usedNames);
1491 numberValuesInRegion(*region);
1495 nameContext.push_back(std::make_tuple(®ion, nextValueID,
1496 nextArgumentID, nextConflictID,
1501 while (usedNames.getCurScope() !=
nullptr)
1502 usedNames.getCurScope()->~UsedNamesScopeTy();
1505 void SSANameState::printValueID(
Value value,
bool printResultNo,
1506 raw_ostream &stream)
const {
1508 stream <<
"<<NULL VALUE>>";
1512 std::optional<int> resultNo;
1513 auto lookupValue = value;
1517 if (
OpResult result = dyn_cast<OpResult>(value))
1518 getResultIDAndNumber(result, lookupValue, resultNo);
1520 auto it = valueIDs.find(lookupValue);
1521 if (it == valueIDs.end()) {
1522 stream <<
"<<UNKNOWN SSA VALUE>>";
1527 if (it->second != NameSentinel) {
1528 stream << it->second;
1530 auto nameIt = valueNames.find(lookupValue);
1531 assert(nameIt != valueNames.end() &&
"Didn't have a name entry?");
1532 stream << nameIt->second;
1535 if (resultNo && printResultNo)
1536 stream <<
'#' << *resultNo;
1539 void SSANameState::printOperationID(
Operation *op, raw_ostream &stream)
const {
1540 auto it = operationIDs.find(op);
1541 if (it == operationIDs.end()) {
1542 stream <<
"<<UNKNOWN OPERATION>>";
1544 stream <<
'%' << it->second;
1549 auto it = opResultGroups.find(op);
1550 return it == opResultGroups.end() ?
ArrayRef<int>() : it->second;
1553 BlockInfo SSANameState::getBlockInfo(
Block *block) {
1554 auto it = blockNames.find(block);
1555 BlockInfo invalidBlock{-1,
"INVALIDBLOCK"};
1556 return it != blockNames.end() ? it->second : invalidBlock;
1559 void SSANameState::shadowRegionArgs(
Region ®ion,
ValueRange namesToUse) {
1560 assert(!region.
empty() &&
"cannot shadow arguments of an empty region");
1562 "incorrect number of names passed in");
1564 "only KnownIsolatedFromAbove ops can shadow names");
1567 for (
unsigned i = 0, e = namesToUse.size(); i != e; ++i) {
1568 auto nameToUse = namesToUse[i];
1569 if (nameToUse ==
nullptr)
1574 llvm::raw_svector_ostream nameStream(nameStr);
1575 printValueID(nameToUse,
true, nameStream);
1578 assert(valueIDs[nameToReplace] == NameSentinel);
1581 auto name = StringRef(nameStream.str()).drop_front();
1584 valueNames[nameToReplace] = name.copy(usedNameAllocator);
1590 StringRef maybeGetValueNameFromLoc(
Value value, StringRef name) {
1592 return maybeNameLoc.getName();
1597 void SSANameState::numberValuesInRegion(
Region ®ion) {
1599 bool opAsmOpInterfaceUsed =
false;
1600 auto setBlockArgNameFn = [&](
Value arg, StringRef name) {
1601 assert(!valueIDs.count(arg) &&
"arg numbered multiple times");
1602 assert(llvm::cast<BlockArgument>(arg).getOwner()->getParent() == ®ion &&
1603 "arg not defined in current region");
1604 opAsmOpInterfaceUsed =
true;
1606 name = maybeGetValueNameFromLoc(arg, name);
1607 setValueName(arg, name);
1612 if (
auto asmInterface = dyn_cast<OpAsmOpInterface>(op))
1613 asmInterface.getAsmBlockArgumentNames(region, setBlockArgNameFn);
1615 if (!opAsmOpInterfaceUsed) {
1617 if (
auto interface = dyn_cast<OpAsmTypeInterface>(arg.
getType())) {
1618 interface.getAsmName(
1619 [&](StringRef name) { setBlockArgNameFn(arg, name); });
1627 unsigned nextBlockID = 0;
1628 for (
auto &block : region) {
1631 auto blockInfoIt = blockNames.insert({&block, {-1,
""}});
1632 if (blockInfoIt.second) {
1636 llvm::raw_string_ostream(name) <<
"^bb" << nextBlockID;
1637 blockInfoIt.first->second.name = StringRef(name).copy(usedNameAllocator);
1639 blockInfoIt.first->second.ordering = nextBlockID++;
1641 numberValuesInBlock(block);
1645 void SSANameState::numberValuesInBlock(
Block &block) {
1650 llvm::raw_svector_ostream specialName(specialNameBuffer);
1652 if (valueIDs.count(arg))
1655 specialNameBuffer.resize(strlen(
"arg"));
1656 specialName << nextArgumentID++;
1658 StringRef specialNameStr = specialName.str();
1660 specialNameStr = maybeGetValueNameFromLoc(arg, specialNameStr);
1661 setValueName(arg, specialNameStr);
1665 for (
auto &op : block)
1666 numberValuesInOp(op);
1669 void SSANameState::numberValuesInOp(
Operation &op) {
1673 bool opAsmOpInterfaceUsed =
false;
1674 auto setResultNameFn = [&](
Value result, StringRef name) {
1675 assert(!valueIDs.count(result) &&
"result numbered multiple times");
1676 assert(result.
getDefiningOp() == &op &&
"result not defined by 'op'");
1677 opAsmOpInterfaceUsed =
true;
1679 name = maybeGetValueNameFromLoc(result, name);
1680 setValueName(result, name);
1683 if (
int resultNo = llvm::cast<OpResult>(result).getResultNumber())
1684 resultGroups.push_back(resultNo);
1687 auto setBlockNameFn = [&](
Block *block, StringRef name) {
1689 "getAsmBlockArgumentNames callback invoked on a block not directly "
1690 "nested under the current operation");
1691 assert(!blockNames.count(block) &&
"block numbered multiple times");
1694 if (name.data() != tmpBuffer.data()) {
1695 tmpBuffer.append(name);
1696 name = tmpBuffer.str();
1698 name = name.copy(usedNameAllocator);
1699 blockNames[block] = {-1, name};
1703 if (OpAsmOpInterface asmInterface = dyn_cast<OpAsmOpInterface>(&op)) {
1704 asmInterface.getAsmBlockNames(setBlockNameFn);
1705 asmInterface.getAsmResultNames(setResultNameFn);
1707 if (!opAsmOpInterfaceUsed) {
1710 bool allHaveOpAsmTypeInterface =
1712 return isa<OpAsmTypeInterface>(type);
1714 if (allHaveOpAsmTypeInterface) {
1716 auto interface = cast<OpAsmTypeInterface>(result.
getType());
1717 interface.getAsmName(
1718 [&](StringRef name) { setResultNameFn(result, name); });
1725 if (numResults == 0) {
1728 if (operationIDs.try_emplace(&op, nextValueID).second)
1737 setValueName(resultBegin, nameLoc.getName());
1742 if (valueIDs.try_emplace(resultBegin, nextValueID).second)
1746 if (resultGroups.size() != 1) {
1747 llvm::array_pod_sort(resultGroups.begin(), resultGroups.end());
1748 opResultGroups.try_emplace(&op, std::move(resultGroups));
1752 void SSANameState::getResultIDAndNumber(
1754 std::optional<int> &lookupResultNo)
const {
1762 auto resultGroupIt = opResultGroups.find(owner);
1763 if (resultGroupIt == opResultGroups.end()) {
1765 lookupResultNo = resultNo;
1772 const auto *it = llvm::upper_bound(resultGroups, resultNo);
1773 int groupResultNo = 0, groupSize = 0;
1776 if (it == resultGroups.end()) {
1777 groupResultNo = resultGroups.back();
1778 groupSize =
static_cast<int>(owner->
getNumResults()) - resultGroups.back();
1781 groupResultNo = *std::prev(it);
1782 groupSize = *it - groupResultNo;
1787 lookupResultNo = resultNo - groupResultNo;
1788 lookupValue = owner->
getResult(groupResultNo);
1791 void SSANameState::setValueName(
Value value, StringRef name) {
1794 valueIDs[value] = nextValueID++;
1798 valueIDs[value] = NameSentinel;
1799 valueNames[value] = uniqueValueName(name);
1802 StringRef SSANameState::uniqueValueName(StringRef name) {
1807 if (!usedNames.count(name)) {
1808 name = name.copy(usedNameAllocator);
1814 probeName.push_back(
'_');
1816 probeName += llvm::utostr(nextConflictID++);
1817 if (!usedNames.count(probeName)) {
1818 name = probeName.str().copy(usedNameAllocator);
1821 probeName.resize(name.size() + 1);
1825 usedNames.insert(name,
char());
1835 class DistinctState {
1841 uint64_t distinctCounter = 0;
1846 uint64_t DistinctState::getId(
DistinctAttr distinctAttr) {
1847 auto [it, inserted] =
1848 distinctAttrMap.try_emplace(distinctAttr, distinctCounter);
1851 return it->getSecond();
1858 AsmParsedResourceEntry::~AsmParsedResourceEntry() =
default;
1859 AsmResourceBuilder::~AsmResourceBuilder() =
default;
1860 AsmResourceParser::~AsmResourceParser() =
default;
1861 AsmResourcePrinter::~AsmResourcePrinter() =
default;
1865 case AsmResourceEntryKind::Blob:
1867 case AsmResourceEntryKind::Bool:
1869 case AsmResourceEntryKind::String:
1872 llvm_unreachable(
"unknown AsmResourceEntryKind");
1876 std::unique_ptr<ResourceCollection> &collection = keyToResources[key.str()];
1878 collection = std::make_unique<ResourceCollection>(key);
1882 std::vector<std::unique_ptr<AsmResourcePrinter>>
1884 std::vector<std::unique_ptr<AsmResourcePrinter>> printers;
1885 for (
auto &it : keyToResources) {
1886 ResourceCollection *collection = it.second.get();
1888 return collection->buildResources(op, builder);
1890 printers.emplace_back(
1896 LogicalResult FallbackAsmResourceMap::ResourceCollection::parseResource(
1900 FailureOr<AsmResourceBlob> blob = entry.
parseAsBlob();
1903 resources.emplace_back(entry.
getKey(), std::move(*blob));
1910 resources.emplace_back(entry.
getKey(), *value);
1917 resources.emplace_back(entry.
getKey(), std::move(*str));
1924 void FallbackAsmResourceMap::ResourceCollection::buildResources(
1926 for (
const auto &entry : resources) {
1927 if (
const auto *value = std::get_if<AsmResourceBlob>(&entry.value))
1929 else if (
const auto *value = std::get_if<bool>(&entry.value))
1931 else if (
const auto *value = std::get_if<std::string>(&entry.value))
1934 llvm_unreachable(
"unknown AsmResourceEntryKind");
1948 : interfaces(op->
getContext()), nameState(op, printerFlags),
1949 printerFlags(printerFlags), locationMap(locationMap) {}
1952 : interfaces(ctx), printerFlags(printerFlags), locationMap(locationMap) {}
1956 aliasState.initialize(op, printerFlags, interfaces);
1976 return llvm::make_pointee_range(externalResourcePrinters);
1986 (*locationMap)[op] = std::make_pair(line, col);
1992 return dialectResources;
1996 return success(cyclicPrintingStack.insert(opaquePointer));
2012 AliasState aliasState;
2015 SSANameState nameState;
2018 DistinctState distinctState;
2034 template <
typename Range>
2038 [&stream](
const auto &dimSize) {
2039 if (ShapedType::isDynamic(dimSize))
2057 return printerFlags;
2061 auto parentThreadId = llvm::get_threadid();
2063 if (parentThreadId == llvm::get_threadid()) {
2065 diag.print(llvm::dbgs());
2066 llvm::dbgs() <<
"\n";
2074 <<
"' failed to verify and will be printed in generic form";
2078 return printerFlags;
2097 return impl->getPrinterFlags();
2101 std::unique_ptr<AsmResourcePrinter> printer) {
2102 impl->externalResourcePrinters.emplace_back(std::move(printer));
2107 return impl->getDialectResources();
2115 : os(os), state(state), printerFlags(state.getPrinterFlags()) {}
2123 printLocation(loc, allowAlias);
2129 if (!isTopLevel && succeeded(state.getAliasState().getAlias(loc, os)))
2133 .Case<OpaqueLoc>([&](OpaqueLoc loc) {
2134 printLocationInternal(loc.getFallbackLocation(), pretty);
2136 .Case<UnknownLoc>([&](UnknownLoc loc) {
2144 os << loc.getFilename().getValue();
2146 printEscapedString(loc.getFilename());
2147 if (loc.getEndColumn() == loc.getStartColumn() &&
2148 loc.getStartLine() == loc.getEndLine()) {
2149 os <<
':' << loc.getStartLine() <<
':' << loc.getStartColumn();
2152 if (loc.getStartLine() == loc.getEndLine()) {
2153 os <<
':' << loc.getStartLine() <<
':' << loc.getStartColumn()
2154 <<
" to :" << loc.getEndColumn();
2157 os <<
':' << loc.getStartLine() <<
':' << loc.getStartColumn() <<
" to "
2158 << loc.getEndLine() <<
':' << loc.getEndColumn();
2160 .Case<NameLoc>([&](NameLoc loc) {
2161 printEscapedString(loc.getName());
2164 auto childLoc = loc.getChildLoc();
2165 if (!llvm::isa<UnknownLoc>(childLoc)) {
2167 printLocationInternal(childLoc, pretty);
2171 .Case<CallSiteLoc>([&](CallSiteLoc loc) {
2176 printLocationInternal(callee, pretty);
2178 if (llvm::isa<NameLoc>(callee)) {
2179 if (llvm::isa<FileLineColLoc>(caller)) {
2182 os << newLine <<
" at ";
2185 os << newLine <<
" at ";
2190 printLocationInternal(caller, pretty);
2194 .Case<FusedLoc>([&](
FusedLoc loc) {
2197 if (
Attribute metadata = loc.getMetadata()) {
2205 [&](Location loc) { printLocationInternal(loc, pretty); },
2206 [&]() { os << ", "; });
2209 .Default([&](LocationAttr loc) {
2210 // Assumes that this is a dialect-specific attribute and prints it
2212 printAttribute(loc);
2218 static void printFloatValue(const APFloat &apValue, raw_ostream &os,
2219 bool *printedHex = nullptr) {
2220 // We would like to output the FP constant value in exponential notation,
2221 // but we cannot do this if doing so will lose precision. Check here to
2222 // make sure that we only output it in exponential format if we can parse
2223 // the value back and get the same value.
2224 bool isInf = apValue.isInfinity();
2225 bool isNaN = apValue.isNaN();
2226 if (!isInf && !isNaN) {
2227 SmallString<128> strValue;
2228 apValue.toString(strValue, /*FormatPrecision=*/6, /*FormatMaxPadding=*/0,
2229 /*TruncateZero=*/false);
2231 // Check to make sure that the stringized number is not some string like
2232 // "Inf" or NaN, that atof will accept, but the lexer will not. Check
2233 // that the string matches the "[-+]?[0-9]" regex.
2234 assert(((strValue[0] >= '0
' && strValue[0] <= '9') ||
2235 ((strValue[0] ==
'-' || strValue[0] ==
'+') &&
2236 (strValue[1] >=
'0' && strValue[1] <=
'9'))) &&
2237 "[-+]?[0-9] regex does not match!");
2241 if (APFloat(apValue.getSemantics(), strValue).bitwiseIsEqual(apValue)) {
2249 apValue.toString(strValue);
2252 if (strValue.str().contains(
'.')) {
2263 APInt apInt = apValue.bitcastToAPInt();
2264 apInt.toString(str, 16,
false,
2271 return printLocationInternal(loc,
true,
true);
2275 printLocationInternal(loc,
false,
true);
2284 if (symName.empty() || !isalpha(symName.front()))
2289 symName = symName.drop_while(
2290 [](
char c) {
return llvm::isAlnum(c) || c ==
'.' || c ==
'_'; });
2291 if (symName.empty())
2296 return symName.front() ==
'<' && symName.back() ==
'>';
2301 StringRef dialectName, StringRef symString) {
2302 os << symPrefix << dialectName;
2307 os <<
'.' << symString;
2311 os << '<' << symString << '>
';
2315 static bool isBareIdentifier(StringRef name) {
2316 // By making this unsigned, the value passed in to isalnum will always be
2317 // in the range 0-255. This is important when building with MSVC because
2318 // its implementation will assert. This situation can arise when dealing
2319 // with UTF-8 multibyte characters.
2320 if (name.empty() || (!isalpha(name[0]) && name[0] != '_
'))
2322 return llvm::all_of(name.drop_front(), [](unsigned char c) {
2323 return isalnum(c) || c == '_
' || c == '$
' || c == '.
';
2329 static void printKeywordOrString(StringRef keyword, raw_ostream &os) {
2330 // If it can be represented as a bare identifier, write it directly.
2331 if (isBareIdentifier(keyword)) {
2336 // Otherwise, output the keyword wrapped in quotes with proper escaping.
2338 printEscapedString(keyword, os);
2345 static void printSymbolReference(StringRef symbolRef, raw_ostream &os) {
2346 if (symbolRef.empty()) {
2347 os << "@<<INVALID EMPTY SYMBOL>>
";
2351 printKeywordOrString(symbolRef, os);
2354 // Print out a valid ElementsAttr that is succinct and can represent any
2355 // potential shape/type, for use when eliding a large ElementsAttr.
2357 // We choose to use a dense resource ElementsAttr literal with conspicuous
2358 // content to hopefully alert readers to the fact that this has been elided.
2359 static void printElidedElementsAttr(raw_ostream &os) {
2360 os << R"(dense_resource<__elided__>)
";
2363 void AsmPrinter::Impl::printResourceHandle(
2364 const AsmDialectResourceHandle &resource) {
2365 auto *interface = cast<OpAsmDialectInterface>(resource.getDialect());
2366 ::printKeywordOrString(interface->getResourceKey(resource), os);
2367 state.getDialectResources()[resource.getDialect()].insert(resource);
2370 LogicalResult AsmPrinter::Impl::printAlias(Attribute attr) {
2371 return state.getAliasState().getAlias(attr, os);
2374 LogicalResult AsmPrinter::Impl::printAlias(Type type) {
2375 return state.getAliasState().getAlias(type, os);
2378 void AsmPrinter::Impl::printAttribute(Attribute attr,
2379 AttrTypeElision typeElision) {
2381 os << "<<NULL ATTRIBUTE>>
";
2385 // Try to print an alias for this attribute.
2386 if (succeeded(printAlias(attr)))
2388 return printAttributeImpl(attr, typeElision);
2390 void AsmPrinter::Impl::printAttributeImpl(Attribute attr,
2391 AttrTypeElision typeElision) {
2392 if (!isa<BuiltinDialect>(attr.getDialect())) {
2393 printDialectAttribute(attr);
2394 } else if (auto opaqueAttr = llvm::dyn_cast<OpaqueAttr>(attr)) {
2395 printDialectSymbol(os, "#
", opaqueAttr.getDialectNamespace(),
2396 opaqueAttr.getAttrData());
2397 } else if (llvm::isa<UnitAttr>(attr)) {
2400 } else if (auto distinctAttr = llvm::dyn_cast<DistinctAttr>(attr)) {
2401 os << "distinct[
" << state.getDistinctState().getId(distinctAttr) << "]<
";
2402 if (!llvm::isa<UnitAttr>(distinctAttr.getReferencedAttr())) {
2403 printAttribute(distinctAttr.getReferencedAttr());
2407 } else if (auto dictAttr = llvm::dyn_cast<DictionaryAttr>(attr)) {
2409 interleaveComma(dictAttr.getValue(),
2410 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2413 } else if (auto intAttr = llvm::dyn_cast<IntegerAttr>(attr)) {
2414 Type intType = intAttr.getType();
2415 if (intType.isSignlessInteger(1)) {
2416 os << (intAttr.getValue().getBoolValue() ? "true" : "false");
2418 // Boolean integer attributes always elides the type.
2422 // Only print attributes as unsigned if they are explicitly unsigned or are
2423 // signless 1-bit values. Indexes, signed values, and multi-bit signless
2424 // values print as signed.
2426 intType.isUnsignedInteger() || intType.isSignlessInteger(1);
2427 intAttr.getValue().print(os, !isUnsigned);
2429 // IntegerAttr elides the type if I64.
2430 if (typeElision == AttrTypeElision::May && intType.isSignlessInteger(64))
2433 } else if (auto floatAttr = llvm::dyn_cast<FloatAttr>(attr)) {
2434 bool printedHex = false;
2435 printFloatValue(floatAttr.getValue(), os, &printedHex);
2437 // FloatAttr elides the type if F64.
2438 if (typeElision == AttrTypeElision::May && floatAttr.getType().isF64() &&
2442 } else if (auto strAttr = llvm::dyn_cast<StringAttr>(attr)) {
2443 printEscapedString(strAttr.getValue());
2445 } else if (auto arrayAttr = llvm::dyn_cast<ArrayAttr>(attr)) {
2447 interleaveComma(arrayAttr.getValue(), [&](Attribute attr) {
2448 printAttribute(attr, AttrTypeElision::May);
2452 } else if (auto affineMapAttr = llvm::dyn_cast<AffineMapAttr>(attr)) {
2453 os << "affine_map<
";
2454 affineMapAttr.getValue().print(os);
2457 // AffineMap always elides the type.
2460 } else if (auto integerSetAttr = llvm::dyn_cast<IntegerSetAttr>(attr)) {
2461 os << "affine_set<
";
2462 integerSetAttr.getValue().print(os);
2465 // IntegerSet always elides the type.
2468 } else if (auto typeAttr = llvm::dyn_cast<TypeAttr>(attr)) {
2469 printType(typeAttr.getValue());
2471 } else if (auto refAttr = llvm::dyn_cast<SymbolRefAttr>(attr)) {
2472 printSymbolReference(refAttr.getRootReference().getValue(), os);
2473 for (FlatSymbolRefAttr nestedRef : refAttr.getNestedReferences()) {
2475 printSymbolReference(nestedRef.getValue(), os);
2478 } else if (auto intOrFpEltAttr =
2479 llvm::dyn_cast<DenseIntOrFPElementsAttr>(attr)) {
2480 if (printerFlags.shouldElideElementsAttr(intOrFpEltAttr)) {
2481 printElidedElementsAttr(os);
2484 printDenseIntOrFPElementsAttr(intOrFpEltAttr, /*allowHex=*/true);
2488 } else if (auto strEltAttr = llvm::dyn_cast<DenseStringElementsAttr>(attr)) {
2489 if (printerFlags.shouldElideElementsAttr(strEltAttr)) {
2490 printElidedElementsAttr(os);
2493 printDenseStringElementsAttr(strEltAttr);
2497 } else if (auto sparseEltAttr = llvm::dyn_cast<SparseElementsAttr>(attr)) {
2498 if (printerFlags.shouldElideElementsAttr(sparseEltAttr.getIndices()) ||
2499 printerFlags.shouldElideElementsAttr(sparseEltAttr.getValues())) {
2500 printElidedElementsAttr(os);
2503 DenseIntElementsAttr indices = sparseEltAttr.getIndices();
2504 if (indices.getNumElements() != 0) {
2505 printDenseIntOrFPElementsAttr(indices, /*allowHex=*/false);
2507 printDenseElementsAttr(sparseEltAttr.getValues(), /*allowHex=*/true);
2511 } else if (auto stridedLayoutAttr = llvm::dyn_cast<StridedLayoutAttr>(attr)) {
2512 stridedLayoutAttr.print(os);
2513 } else if (auto denseArrayAttr = llvm::dyn_cast<DenseArrayAttr>(attr)) {
2515 printType(denseArrayAttr.getElementType());
2516 if (!denseArrayAttr.empty()) {
2518 printDenseArrayAttr(denseArrayAttr);
2522 } else if (auto resourceAttr =
2523 llvm::dyn_cast<DenseResourceElementsAttr>(attr)) {
2524 os << "dense_resource<
";
2525 printResourceHandle(resourceAttr.getRawHandle());
2527 } else if (auto locAttr = llvm::dyn_cast<LocationAttr>(attr)) {
2528 printLocation(locAttr);
2530 llvm::report_fatal_error("Unknown builtin attribute
");
2532 // Don't print the type if we must elide it, or if it is a None type.
2533 if (typeElision != AttrTypeElision::Must) {
2534 if (auto typedAttr = llvm::dyn_cast<TypedAttr>(attr)) {
2535 Type attrType = typedAttr.getType();
2536 if (!llvm::isa<NoneType>(attrType)) {
2538 printType(attrType);
2545 static void printDenseIntElement(const APInt &value, raw_ostream &os,
2547 if (type.isInteger(1))
2548 os << (value.getBoolValue() ? "
true" : "false");
2550 value.print(os, !type.isUnsignedInteger());
2554 printDenseElementsAttrImpl(bool isSplat, ShapedType type, raw_ostream &os,
2555 function_ref<void(unsigned)> printEltFn) {
2556 // Special case for 0-d and splat tensors.
2558 return printEltFn(0);
2560 // Special case for degenerate tensors.
2561 auto numElements = type.getNumElements();
2562 if (numElements == 0)
2565 // We use a mixed-radix counter to iterate through the shape. When we bump a
2566 // non-least-significant digit, we emit a close bracket. When we next emit an
2567 // element we re-open all closed brackets.
2569 // The mixed-radix counter, with radices in 'shape'.
2570 int64_t rank = type.getRank();
2571 SmallVector<unsigned, 4> counter(rank, 0);
2572 // The number of brackets that have been opened and not closed.
2573 unsigned openBrackets = 0;
2575 auto shape = type.getShape();
2576 auto bumpCounter = [&] {
2577 // Bump the least significant digit.
2578 ++counter[rank - 1];
2579 // Iterate backwards bubbling back the increment.
2580 for (unsigned i = rank - 1; i > 0; --i)
2581 if (counter[i] >= shape[i]) {
2582 // Index 'i' is rolled over. Bump (i-1) and close a bracket.
2590 for (unsigned idx = 0, e = numElements; idx != e; ++idx) {
2593 while (openBrackets++ < rank)
2595 openBrackets = rank;
2599 while (openBrackets-- > 0)
2603 void AsmPrinter::Impl::printDenseElementsAttr(DenseElementsAttr attr,
2605 if (auto stringAttr = llvm::dyn_cast<DenseStringElementsAttr>(attr))
2606 return printDenseStringElementsAttr(stringAttr);
2608 printDenseIntOrFPElementsAttr(llvm::cast<DenseIntOrFPElementsAttr>(attr),
2612 void AsmPrinter::Impl::printDenseIntOrFPElementsAttr(
2613 DenseIntOrFPElementsAttr attr, bool allowHex) {
2614 auto type = attr.getType();
2615 auto elementType = type.getElementType();
2617 // Check to see if we should format this attribute as a hex string.
2618 if (allowHex && printerFlags.shouldPrintElementsAttrWithHex(attr)) {
2619 ArrayRef<char> rawData = attr.getRawData();
2620 if (llvm::endianness::native == llvm::endianness::big) {
2621 // Convert endianess in big-endian(BE) machines. `rawData` is BE in BE
2622 // machines. It is converted here to print in LE format.
2623 SmallVector<char, 64> outDataVec(rawData.size());
2624 MutableArrayRef<char> convRawData(outDataVec);
2625 DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
2626 rawData, convRawData, type);
2627 printHexString(convRawData);
2629 printHexString(rawData);
2635 if (ComplexType complexTy = llvm::dyn_cast<ComplexType>(elementType)) {
2636 Type complexElementType = complexTy.getElementType();
2637 // Note: The if and else below had a common lambda function which invoked
2638 // printDenseElementsAttrImpl. This lambda was hitting a bug in gcc 9.1,9.2
2639 // and hence was replaced.
2640 if (llvm::isa<IntegerType>(complexElementType)) {
2641 auto valueIt = attr.value_begin<std::complex<APInt>>();
2642 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2643 auto complexValue = *(valueIt + index);
2645 printDenseIntElement(complexValue.real(), os, complexElementType);
2647 printDenseIntElement(complexValue.imag(), os, complexElementType);
2651 auto valueIt = attr.value_begin<std::complex<APFloat>>();
2652 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2653 auto complexValue = *(valueIt + index);
2655 printFloatValue(complexValue.real(), os);
2657 printFloatValue(complexValue.imag(), os);
2661 } else if (elementType.isIntOrIndex()) {
2662 auto valueIt = attr.value_begin<APInt>();
2663 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2664 printDenseIntElement(*(valueIt + index), os, elementType);
2667 assert(llvm::isa<FloatType>(elementType) && "unexpected element type
");
2668 auto valueIt = attr.value_begin<APFloat>();
2669 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2670 printFloatValue(*(valueIt + index), os);
2675 void AsmPrinter::Impl::printDenseStringElementsAttr(
2676 DenseStringElementsAttr attr) {
2677 ArrayRef<StringRef> data = attr.getRawStringData();
2678 auto printFn = [&](unsigned index) { printEscapedString(data[index]); };
2679 printDenseElementsAttrImpl(attr.isSplat(), attr.getType(), os, printFn);
2682 void AsmPrinter::Impl::printDenseArrayAttr(DenseArrayAttr attr) {
2683 Type type = attr.getElementType();
2684 unsigned bitwidth = type.isInteger(1) ? 8 : type.getIntOrFloatBitWidth();
2685 unsigned byteSize = bitwidth / 8;
2686 ArrayRef<char> data = attr.getRawData();
2688 auto printElementAt = [&](unsigned i) {
2689 APInt value(bitwidth, 0);
2691 llvm::LoadIntFromMemory(
2692 value, reinterpret_cast<const uint8_t *>(data.begin() + byteSize * i),
2695 // Print the data as-is or as a float.
2696 if (type.isIntOrIndex()) {
2697 printDenseIntElement(value, getStream(), type);
2699 APFloat fltVal(llvm::cast<FloatType>(type).getFloatSemantics(), value);
2700 printFloatValue(fltVal, getStream());
2703 llvm::interleaveComma(llvm::seq<unsigned>(0, attr.size()), getStream(),
2707 void AsmPrinter::Impl::printType(Type type) {
2709 os << "<<NULL TYPE>>
";
2713 // Try to print an alias for this type.
2714 if (succeeded(printAlias(type)))
2716 return printTypeImpl(type);
2719 void AsmPrinter::Impl::printTypeImpl(Type type) {
2720 TypeSwitch<Type>(type)
2721 .Case<OpaqueType>([&](OpaqueType opaqueTy) {
2722 printDialectSymbol(os, "!
", opaqueTy.getDialectNamespace(),
2723 opaqueTy.getTypeData());
2725 .Case<IndexType>([&](Type) { os << "index
"; })
2726 .Case<Float4E2M1FNType>([&](Type) { os << "f4E2M1FN
"; })
2727 .Case<Float6E2M3FNType>([&](Type) { os << "f6E2M3FN
"; })
2728 .Case<Float6E3M2FNType>([&](Type) { os << "f6E3M2FN
"; })
2729 .Case<Float8E5M2Type>([&](Type) { os << "f8E5M2
"; })
2730 .Case<Float8E4M3Type>([&](Type) { os << "f8E4M3
"; })
2731 .Case<Float8E4M3FNType>([&](Type) { os << "f8E4M3FN
"; })
2732 .Case<Float8E5M2FNUZType>([&](Type) { os << "f8E5M2FNUZ
"; })
2733 .Case<Float8E4M3FNUZType>([&](Type) { os << "f8E4M3FNUZ
"; })
2734 .Case<Float8E4M3B11FNUZType>([&](Type) { os << "f8E4M3B11FNUZ
"; })
2735 .Case<Float8E3M4Type>([&](Type) { os << "f8E3M4
"; })
2736 .Case<Float8E8M0FNUType>([&](Type) { os << "f8E8M0FNU
"; })
2737 .Case<BFloat16Type>([&](Type) { os << "bf16"; })
2738 .Case<Float16Type>([&](Type) { os << "f16"; })
2739 .Case<FloatTF32Type>([&](Type) { os << "tf32
"; })
2740 .Case<Float32Type>([&](Type) { os << "f32
"; })
2741 .Case<Float64Type>([&](Type) { os << "f64
"; })
2742 .Case<Float80Type>([&](Type) { os << "f80
"; })
2743 .Case<Float128Type>([&](Type) { os << "f128
"; })
2744 .Case<IntegerType>([&](IntegerType integerTy) {
2745 if (integerTy.isSigned())
2747 else if (integerTy.isUnsigned())
2749 os << 'i' << integerTy.getWidth();
2751 .Case<FunctionType>([&](FunctionType funcTy) {
2753 interleaveComma(funcTy.getInputs(), [&](Type ty) { printType(ty); });
2755 ArrayRef<Type> results = funcTy.getResults();
2756 if (results.size() == 1 && !llvm::isa<FunctionType>(results[0])) {
2757 printType(results[0]);
2760 interleaveComma(results, [&](Type ty) { printType(ty); });
2764 .Case<VectorType>([&](VectorType vectorTy) {
2765 auto scalableDims = vectorTy.getScalableDims();
2767 auto vShape = vectorTy.getShape();
2768 unsigned lastDim = vShape.size();
2769 unsigned dimIdx = 0;
2770 for (dimIdx = 0; dimIdx < lastDim; dimIdx++) {
2771 if (!scalableDims.empty() && scalableDims[dimIdx])
2773 os << vShape[dimIdx];
2774 if (!scalableDims.empty() && scalableDims[dimIdx])
2778 printType(vectorTy.getElementType());
2781 .Case<RankedTensorType>([&](RankedTensorType tensorTy) {
2783 printDimensionList(tensorTy.getShape());
2784 if (!tensorTy.getShape().empty())
2786 printType(tensorTy.getElementType());
2787 // Only print the encoding attribute value if set.
2788 if (tensorTy.getEncoding()) {
2790 printAttribute(tensorTy.getEncoding());
2794 .Case<UnrankedTensorType>([&](UnrankedTensorType tensorTy) {
2796 printType(tensorTy.getElementType());
2799 .Case<MemRefType>([&](MemRefType memrefTy) {
2801 printDimensionList(memrefTy.getShape());
2802 if (!memrefTy.getShape().empty())
2804 printType(memrefTy.getElementType());
2805 MemRefLayoutAttrInterface layout = memrefTy.getLayout();
2806 if (!llvm::isa<AffineMapAttr>(layout) || !layout.isIdentity()) {
2808 printAttribute(memrefTy.getLayout(), AttrTypeElision::May);
2810 // Only print the memory space if it is the non-default one.
2811 if (memrefTy.getMemorySpace()) {
2813 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2817 .Case<UnrankedMemRefType>([&](UnrankedMemRefType memrefTy) {
2819 printType(memrefTy.getElementType());
2820 // Only print the memory space if it is the non-default one.
2821 if (memrefTy.getMemorySpace()) {
2823 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2827 .Case<ComplexType>([&](ComplexType complexTy) {
2829 printType(complexTy.getElementType());
2832 .Case<TupleType>([&](TupleType tupleTy) {
2834 interleaveComma(tupleTy.getTypes(),
2835 [&](Type type) { printType(type); });
2838 .Case<NoneType>([&](Type) { os << "none
"; })
2839 .Case<GraphType>([&](GraphType graphTy) {
2841 interleaveComma(graphTy.getInputs(), [&](Type ty) { printType(ty); });
2843 ArrayRef<Type> results = graphTy.getResults();
2844 if (results.size() == 1 && !isa<FunctionType, GraphType>(results[0])) {
2845 printType(results[0]);
2848 interleaveComma(results, [&](Type ty) { printType(ty); });
2852 .Default([&](Type type) { return printDialectType(type); });
2855 void AsmPrinter::Impl::printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
2856 ArrayRef<StringRef> elidedAttrs,
2858 // If there are no attributes, then there is nothing to be done.
2862 // Functor used to print a filtered attribute list.
2863 auto printFilteredAttributesFn = [&](auto filteredAttrs) {
2864 // Print the 'attributes' keyword if necessary.
2866 os << " attributes
";
2868 // Otherwise, print them all out in braces.
2870 interleaveComma(filteredAttrs,
2871 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2875 // If no attributes are elided, we can directly print with no filtering.
2876 if (elidedAttrs.empty())
2877 return printFilteredAttributesFn(attrs);
2879 // Otherwise, filter out any attributes that shouldn't be included.
2880 llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
2882 auto filteredAttrs = llvm::make_filter_range(attrs, [&](NamedAttribute attr) {
2883 return !elidedAttrsSet.contains(attr.getName().strref());
2885 if (!filteredAttrs.empty())
2886 printFilteredAttributesFn(filteredAttrs);
2888 void AsmPrinter::Impl::printNamedAttribute(NamedAttribute attr) {
2889 // Print the name without quotes if possible.
2890 ::printKeywordOrString(attr.getName().strref(), os);
2892 // Pretty printing elides the attribute value for unit attributes.
2893 if (llvm::isa<UnitAttr>(attr.getValue()))
2897 printAttribute(attr.getValue());
2900 void AsmPrinter::Impl::printDialectAttribute(Attribute attr) {
2901 auto &dialect = attr.getDialect();
2903 // Ask the dialect to serialize the attribute to a string.
2904 std::string attrName;
2906 llvm::raw_string_ostream attrNameStr(attrName);
2907 Impl subPrinter(attrNameStr, state);
2908 DialectAsmPrinter printer(subPrinter);
2909 dialect.printAttribute(attr, printer);
2911 printDialectSymbol(os, "#
", dialect.getNamespace(), attrName);
2914 void AsmPrinter::Impl::printDialectType(Type type) {
2915 auto &dialect = type.getDialect();
2917 // Ask the dialect to serialize the type to a string.
2918 std::string typeName;
2920 llvm::raw_string_ostream typeNameStr(typeName);
2921 Impl subPrinter(typeNameStr, state);
2922 DialectAsmPrinter printer(subPrinter);
2923 dialect.printType(type, printer);
2925 printDialectSymbol(os, "!
", dialect.getNamespace(), typeName);
2928 void AsmPrinter::Impl::printEscapedString(StringRef str) {
2930 llvm::printEscapedString(str, os);
2935 os <<
"\"0x" << llvm::toHex(str) <<
"\"";
2938 printHexString(StringRef(data.data(), data.size()));
2942 return state.pushCyclicPrinting(opaquePointer);
2958 assert(
impl &&
"expected AsmPrinter::getStream to be overriden");
2959 return impl->getStream();
2964 assert(
impl &&
"expected AsmPrinter::printFloat to be overriden");
2969 assert(
impl &&
"expected AsmPrinter::printType to be overriden");
2970 impl->printType(type);
2974 assert(
impl &&
"expected AsmPrinter::printAttribute to be overriden");
2975 impl->printAttribute(attr);
2979 assert(
impl &&
"expected AsmPrinter::printAlias to be overriden");
2980 return impl->printAlias(attr);
2984 assert(
impl &&
"expected AsmPrinter::printAlias to be overriden");
2985 return impl->printAlias(type);
2990 "expected AsmPrinter::printAttributeWithoutType to be overriden");
2995 assert(
impl &&
"expected AsmPrinter::printNamedAttribute to be overriden");
2996 impl->printNamedAttribute(attr);
3000 assert(
impl &&
"expected AsmPrinter::printKeywordOrString to be overriden");
3005 assert(
impl &&
"expected AsmPrinter::printString to be overriden");
3007 printEscapedString(keyword,
getStream());
3012 assert(
impl &&
"expected AsmPrinter::printSymbolName to be overriden");
3017 assert(
impl &&
"expected AsmPrinter::printResourceHandle to be overriden");
3018 impl->printResourceHandle(resource);
3026 return impl->pushCyclicPrinting(opaquePointer);
3037 printAffineExprInternal(expr, BindingStrength::Weak, printValueName);
3043 const char *binopSpelling =
nullptr;
3046 unsigned pos = cast<AffineSymbolExpr>(expr).getPosition();
3048 printValueName(pos,
true);
3054 unsigned pos = cast<AffineDimExpr>(expr).getPosition();
3056 printValueName(pos,
false);
3062 os << cast<AffineConstantExpr>(expr).getValue();
3065 binopSpelling =
" + ";
3068 binopSpelling =
" * ";
3071 binopSpelling =
" floordiv ";
3074 binopSpelling =
" ceildiv ";
3077 binopSpelling =
" mod ";
3081 auto binOp = cast<AffineBinaryOpExpr>(expr);
3087 if (enclosingTightness == BindingStrength::Strong)
3091 auto rhsConst = dyn_cast<AffineConstantExpr>(rhsExpr);
3093 rhsConst.getValue() == -1) {
3095 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
3096 if (enclosingTightness == BindingStrength::Strong)
3101 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
3103 os << binopSpelling;
3104 printAffineExprInternal(rhsExpr, BindingStrength::Strong, printValueName);
3106 if (enclosingTightness == BindingStrength::Strong)
3112 if (enclosingTightness == BindingStrength::Strong)
3117 if (
auto rhs = dyn_cast<AffineBinaryOpExpr>(rhsExpr)) {
3120 if (
auto rrhs = dyn_cast<AffineConstantExpr>(rrhsExpr)) {
3121 if (rrhs.getValue() == -1) {
3122 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
3126 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
3129 printAffineExprInternal(rhs.getLHS(), BindingStrength::Weak,
3133 if (enclosingTightness == BindingStrength::Strong)
3138 if (rrhs.getValue() < -1) {
3139 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
3142 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
3144 os <<
" * " << -rrhs.getValue();
3145 if (enclosingTightness == BindingStrength::Strong)
3154 if (
auto rhsConst = dyn_cast<AffineConstantExpr>(rhsExpr)) {
3155 if (rhsConst.getValue() < 0) {
3156 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
3157 os <<
" - " << -rhsConst.getValue();
3158 if (enclosingTightness == BindingStrength::Strong)
3164 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
3167 printAffineExprInternal(rhsExpr, BindingStrength::Weak, printValueName);
3169 if (enclosingTightness == BindingStrength::Strong)
3174 printAffineExprInternal(expr, BindingStrength::Weak);
3175 isEq ? os <<
" == 0" : os <<
" >= 0";
3181 for (
int i = 0; i < (int)map.
getNumDims() - 1; ++i)
3182 os <<
'd' << i <<
", ";
3191 os <<
's' << i <<
", ";
3200 [&](
AffineExpr expr) { printAffineExpr(expr); });
3207 for (
unsigned i = 1; i < set.
getNumDims(); ++i)
3208 os <<
'd' << i - 1 <<
", ";
3217 os <<
's' << i <<
", ";
3226 for (
int i = 1; i < numConstraints; ++i) {
3230 if (numConstraints >= 1)
3231 printAffineConstraint(set.
getConstraint(numConstraints - 1),
3232 set.
isEq(numConstraints - 1));
3247 explicit OperationPrinter(raw_ostream &os,
AsmStateImpl &state)
3251 void printTopLevelOperation(
Operation *op);
3255 void printFullOpWithIndentAndLoc(
Operation *op);
3261 void printCustomOrGenericOp(
Operation *op)
override;
3263 void printGenericOp(
Operation *op,
bool printOpName)
override;
3266 void printBlockName(
Block *block);
3271 void print(
Block *block,
bool printBlockArgs =
true,
3272 bool printBlockTerminator =
true);
3275 void printValueID(
Value value,
bool printResultNo =
true,
3276 raw_ostream *streamOverride =
nullptr)
const;
3280 raw_ostream *streamOverride =
nullptr)
const;
3288 void printOptionalLocationSpecifier(
Location loc)
override {
3289 printTrailingLocation(loc);
3296 os.indent(currentIndent);
3300 void increaseIndent()
override { currentIndent += indentWidth; }
3303 void decreaseIndent()
override { currentIndent -= indentWidth; }
3312 bool omitType =
false)
override;
3315 void printOperand(
Value value)
override { printValueID(value); }
3316 void printOperand(
Value value, raw_ostream &os)
override {
3317 printValueID(value,
true, &os);
3325 void printOptionalAttrDictWithKeyword(
3333 void printSuccessor(
Block *successor)
override;
3337 void printSuccessorAndUseList(
Block *successor,
3342 bool printBlockTerminators,
bool printEmptyBlock)
override;
3349 state.getSSANameState().shadowRegionArgs(region, namesToUse);
3354 void printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3369 void printValueUsers(
Value value);
3373 void printUserIDs(
Operation *user,
bool prefixComma =
false);
3381 using PrintFn =
function_ref<void(StringRef, ValueFn)>;
3383 ResourceBuilder(PrintFn printFn) : printFn(printFn) {}
3384 ~ResourceBuilder()
override =
default;
3386 void buildBool(StringRef key,
bool data)
final {
3387 printFn(key, [&](raw_ostream &os) { os << (data ?
"true" :
"false"); });
3390 void buildString(StringRef key, StringRef data)
final {
3391 printFn(key, [&](raw_ostream &os) {
3393 llvm::printEscapedString(data, os);
3399 uint32_t dataAlignment)
final {
3400 printFn(key, [&](raw_ostream &os) {
3402 llvm::support::ulittle32_t dataAlignmentLE(dataAlignment);
3404 << llvm::toHex(StringRef(
reinterpret_cast<char *
>(&dataAlignmentLE),
3405 sizeof(dataAlignment)))
3406 << llvm::toHex(StringRef(data.data(), data.size())) <<
"\"";
3415 void printFileMetadataDictionary(
Operation *op);
3421 void printResourceFileMetadata(
function_ref<
void()> checkAddMetadataDict,
3432 const static unsigned indentWidth = 2;
3435 unsigned currentIndent = 0;
3439 void OperationPrinter::printTopLevelOperation(
Operation *op) {
3441 state.getAliasState().printNonDeferredAliases(*
this, newLine);
3444 printFullOpWithIndentAndLoc(op);
3448 state.getAliasState().printDeferredAliases(*
this, newLine);
3451 printFileMetadataDictionary(op);
3454 void OperationPrinter::printFileMetadataDictionary(
Operation *op) {
3455 bool sawMetadataEntry =
false;
3456 auto checkAddMetadataDict = [&] {
3457 if (!std::exchange(sawMetadataEntry,
true))
3458 os << newLine <<
"{-#" << newLine;
3462 printResourceFileMetadata(checkAddMetadataDict, op);
3465 if (sawMetadataEntry)
3466 os << newLine <<
"#-}" << newLine;
3469 void OperationPrinter::printResourceFileMetadata(
3472 bool hadResource =
false;
3473 bool needResourceComma =
false;
3474 bool needEntryComma =
false;
3475 auto processProvider = [&](StringRef dictName, StringRef name,
auto &provider,
3476 auto &&...providerArgs) {
3477 bool hadEntry =
false;
3478 auto printFn = [&](StringRef key, ResourceBuilder::ValueFn valueFn) {
3479 checkAddMetadataDict();
3481 std::string resourceStr;
3482 auto printResourceStr = [&](raw_ostream &os) { os << resourceStr; };
3483 std::optional<uint64_t> charLimit =
3485 if (charLimit.has_value()) {
3487 if (charLimit.value() == 0)
3490 llvm::raw_string_ostream ss(resourceStr);
3494 if (resourceStr.size() > charLimit.value())
3498 valueFn = printResourceStr;
3502 if (!std::exchange(hadResource,
true)) {
3503 if (needResourceComma)
3504 os <<
"," << newLine;
3505 os <<
" " << dictName <<
"_resources: {" << newLine;
3508 if (!std::exchange(hadEntry,
true)) {
3510 os <<
"," << newLine;
3511 os <<
" " << name <<
": {" << newLine;
3513 os <<
"," << newLine;
3521 ResourceBuilder entryBuilder(printFn);
3522 provider.buildResources(op, providerArgs..., entryBuilder);
3524 needEntryComma |= hadEntry;
3526 os << newLine <<
" }";
3532 auto &dialectResources = state.getDialectResources();
3533 StringRef name = interface.getDialect()->getNamespace();
3534 auto it = dialectResources.find(interface.getDialect());
3535 if (it != dialectResources.end())
3536 processProvider(
"dialect", name, interface, it->second);
3538 processProvider(
"dialect", name, interface,
3542 os << newLine <<
" }";
3546 needEntryComma =
false;
3547 needResourceComma = hadResource;
3548 hadResource =
false;
3549 for (
const auto &printer : state.getResourcePrinters())
3550 processProvider(
"external", printer.getName(), printer);
3552 os << newLine <<
" }";
3560 void OperationPrinter::printRegionArgument(
BlockArgument arg,
3568 printOptionalAttrDict(argAttrs);
3570 printTrailingLocation(arg.
getLoc(),
false);
3573 void OperationPrinter::printFullOpWithIndentAndLoc(
Operation *op) {
3575 state.registerOperationLocation(op, newLine.curLine, currentIndent);
3577 os.indent(currentIndent);
3579 printTrailingLocation(op->
getLoc());
3581 printUsersComment(op);
3584 void OperationPrinter::printFullOp(
Operation *op) {
3586 auto printResultGroup = [&](
size_t resultNo,
size_t resultCount) {
3587 printValueID(op->
getResult(resultNo),
false);
3588 if (resultCount > 1)
3589 os <<
':' << resultCount;
3593 ArrayRef<int> resultGroups = state.getSSANameState().getOpResultGroups(op);
3594 if (!resultGroups.empty()) {
3597 interleaveComma(llvm::seq<int>(0, resultGroups.size() - 1), [&](
int i) {
3598 printResultGroup(resultGroups[i],
3599 resultGroups[i + 1] - resultGroups[i]);
3602 printResultGroup(resultGroups.back(), numResults - resultGroups.back());
3605 printResultGroup(0, numResults);
3611 printCustomOrGenericOp(op);
3614 void OperationPrinter::printUsersComment(
Operation *op) {
3618 printOperationID(op);
3619 }
else if (numResults && op->
use_empty()) {
3621 }
else if (numResults && !op->
use_empty()) {
3624 unsigned usedInNResults = 0;
3625 unsigned usedInNOperations = 0;
3628 if (userSet.insert(user).second) {
3629 ++usedInNOperations;
3630 usedInNResults += user->getNumResults();
3635 bool exactlyOneUniqueUse =
3636 usedInNResults <= 1 && usedInNOperations <= 1 && numResults == 1;
3637 os <<
" // " << (exactlyOneUniqueUse ?
"user" :
"users") <<
": ";
3638 bool shouldPrintBrackets = numResults > 1;
3639 auto printOpResult = [&](
OpResult opResult) {
3640 if (shouldPrintBrackets)
3642 printValueUsers(opResult);
3643 if (shouldPrintBrackets)
3647 interleaveComma(op->
getResults(), printOpResult);
3651 void OperationPrinter::printUsersComment(
BlockArgument arg) {
3657 os <<
" is used by ";
3658 printValueUsers(arg);
3663 void OperationPrinter::printValueUsers(
Value value) {
3671 if (userSet.insert(user).second)
3672 printUserIDs(user, index);
3676 void OperationPrinter::printUserIDs(
Operation *user,
bool prefixComma) {
3681 printOperationID(user);
3684 [
this](
Value result) { printValueID(result); });
3688 void OperationPrinter::printCustomOrGenericOp(
Operation *op) {
3694 opInfo->printAssembly(op, *
this, defaultDialectStack.back());
3699 if (
auto opPrinter = dialect->getOperationPrinter(op)) {
3704 if (name.count(
'.') == 1)
3705 name.consume_front((defaultDialectStack.back() +
".").str());
3709 opPrinter(op, *
this);
3716 printGenericOp(op,
true);
3719 void OperationPrinter::printGenericOp(
Operation *op,
bool printOpName) {
3723 interleaveComma(op->
getOperands(), [&](
Value value) { printValueID(value); });
3730 [&](
Block *successor) { printBlockName(successor); });
3742 if (op->getNumRegions() != 0) {
3744 interleaveComma(op->getRegions(), [&](Region ®ion) {
3745 printRegion(region, /*printEntryBlockArgs=*/true,
3746 /*printBlockTerminators=*/true, /*printEmptyBlock=*/true);
3751 printOptionalAttrDict(op->getPropertiesStorage()
3752 ? llvm::to_vector(op->getDiscardableAttrs())
3755 // Print the type signature of the operation.
3757 printFunctionalType(op);
3760 void OperationPrinter::printBlockName(Block *block) {
3761 os << state.getSSANameState().getBlockInfo(block).name;
3764 void OperationPrinter::print(Block *block, bool printBlockArgs,
3765 bool printBlockTerminator) {
3766 // Print the block label and argument list if requested.
3767 if (printBlockArgs) {
3768 os.indent(currentIndent);
3769 printBlockName(block);
3771 // Print the argument list if non-empty.
3772 if (!block->args_empty()) {
3774 interleaveComma(block->getArguments(), [&](BlockArgument arg) {
3777 printType(arg.getType());
3778 // TODO: We should allow location aliases on block arguments.
3779 printTrailingLocation(arg.getLoc(), /*allowAlias*/ false);
3785 // Print out some context information about the predecessors of this block.
3786 if (!block->getParent()) {
3787 os << " // block is not in a region!";
3788 } else if (block->hasNoPredecessors()) {
3789 if (!block->isEntryBlock())
3790 os << " // no predecessors";
3791 } else if (auto *pred = block->getSinglePredecessor()) {
3793 printBlockName(pred);
3795 // We want to print the predecessors in a stable order, not in
3796 // whatever order the use-list is in, so gather and sort them.
3797 SmallVector<BlockInfo, 4> predIDs;
3798 for (auto *pred : block->getPredecessors())
3799 predIDs.push_back(state.getSSANameState().getBlockInfo(pred));
3800 llvm::sort(predIDs, [](BlockInfo lhs, BlockInfo rhs) {
3801 return lhs.ordering < rhs.ordering;
3804 os << " // " << predIDs.size() << " preds: ";
3806 interleaveComma(predIDs, [&](BlockInfo pred) { os << pred.name; });
3811 currentIndent += indentWidth;
3813 if (printerFlags.shouldPrintValueUsers()) {
3814 for (BlockArgument arg : block->getArguments()) {
3815 os.indent(currentIndent);
3816 printUsersComment(arg);
3820 bool hasTerminator =
3821 !block->empty() && block->back().hasTrait<OpTrait::IsTerminator>();
3822 auto range = llvm::make_range(
3824 std::prev(block->end(),
3825 (!hasTerminator || printBlockTerminator) ? 0 : 1));
3826 for (auto &op : range) {
3827 printFullOpWithIndentAndLoc(&op);
3830 currentIndent -= indentWidth;
3833 void OperationPrinter::printValueID(Value value, bool printResultNo,
3834 raw_ostream *streamOverride) const {
3835 state.getSSANameState().printValueID(value, printResultNo,
3836 streamOverride ? *streamOverride : os);
3839 void OperationPrinter::printOperationID(Operation *op,
3840 raw_ostream *streamOverride) const {
3841 state.getSSANameState().printOperationID(op, streamOverride ? *streamOverride
3845 void OperationPrinter::printSuccessor(Block *successor) {
3846 printBlockName(successor);
3849 void OperationPrinter::printSuccessorAndUseList(Block *successor,
3850 ValueRange succOperands) {
3851 printBlockName(successor);
3852 if (succOperands.empty())
3856 interleaveComma(succOperands,
3857 [this](Value operand) { printValueID(operand); });
3859 interleaveComma(succOperands,
3860 [this](Value operand) { printType(operand.getType()); });
3864 void OperationPrinter::printRegion(Region ®ion, bool printEntryBlockArgs,
3865 bool printBlockTerminators,
3866 bool printEmptyBlock) {
3867 if (printerFlags.shouldSkipRegions()) {
3871 os << "{" << newLine;
3872 if (!region.empty()) {
3873 auto restoreDefaultDialect =
3874 llvm::make_scope_exit([&]() { defaultDialectStack.pop_back(); });
3875 if (auto iface = dyn_cast<OpAsmOpInterface>(region.getParentOp()))
3876 defaultDialectStack.push_back(iface.getDefaultDialect());
3878 defaultDialectStack.push_back("");
3880 auto *entryBlock = ®ion.front();
3881 // Force printing the block header if printEmptyBlock is set and the block
3882 // is empty or if printEntryBlockArgs is set and there are arguments to
3884 bool shouldAlwaysPrintBlockHeader =
3885 (printEmptyBlock && entryBlock->empty()) ||
3886 (printEntryBlockArgs && entryBlock->getNumArguments() != 0);
3887 print(entryBlock, shouldAlwaysPrintBlockHeader, printBlockTerminators);
3888 for (auto &b : llvm::drop_begin(region.getBlocks(), 1))
3891 os.indent(currentIndent) << "}";
3894 void OperationPrinter::printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3895 ValueRange operands) {
3897 os << "<<NULL AFFINE MAP>>";
3900 AffineMap map = mapAttr.getValue();
3901 unsigned numDims = map.getNumDims();
3902 auto printValueName = [&](unsigned pos, bool isSymbol) {
3903 unsigned index = isSymbol ? numDims + pos : pos;
3904 assert(index < operands.size());
3907 printValueID(operands[index]);
3912 interleaveComma(map.getResults(), [&](AffineExpr expr) {
3913 printAffineExpr(expr, printValueName);
3917 void OperationPrinter::printAffineExprOfSSAIds(AffineExpr expr,
3918 ValueRange dimOperands,
3919 ValueRange symOperands) {
3920 auto printValueName = [&](unsigned pos, bool isSymbol) {
3922 return printValueID(dimOperands[pos]);
3924 printValueID(symOperands[pos]);
3927 printAffineExpr(expr, printValueName);
3930 //===----------------------------------------------------------------------===//
3931 // print and dump methods
3932 //===----------------------------------------------------------------------===//
3934 void Attribute::print(raw_ostream &os, bool elideType) const {
3936 os << "<<NULL ATTRIBUTE>>";
3940 AsmState state(getContext());
3941 print(os, state, elideType);
3943 void Attribute::print(raw_ostream &os, AsmState &state, bool elideType) const {
3944 using AttrTypeElision = AsmPrinter::Impl::AttrTypeElision;
3945 AsmPrinter::Impl(os, state.getImpl())
3946 .printAttribute(*this, elideType ? AttrTypeElision::Must
3947 : AttrTypeElision::Never);
3950 void Attribute::dump() const {
3951 print(llvm::errs());
3952 llvm::errs() << "\n";
3955 void Attribute::printStripped(raw_ostream &os, AsmState &state) const {
3957 os << "<<NULL ATTRIBUTE>>";
3961 AsmPrinter::Impl subPrinter(os, state.getImpl());
3962 if (succeeded(subPrinter.printAlias(*this)))
3965 auto &dialect = this->getDialect();
3966 uint64_t posPrior = os.tell();
3967 DialectAsmPrinter printer(subPrinter);
3968 dialect.printAttribute(*this, printer);
3969 if (posPrior != os.tell())
3972 // Fallback to printing with prefix if the above failed to write anything
3973 // to the output stream.
3976 void Attribute::printStripped(raw_ostream &os) const {
3978 os << "<<NULL ATTRIBUTE>>";
3982 AsmState state(getContext());
3983 printStripped(os, state);
3986 void Type::print(raw_ostream &os) const {
3988 os << "<<NULL TYPE>>";
3992 AsmState state(getContext());
3995 void Type::print(raw_ostream &os, AsmState &state) const {
3996 AsmPrinter::Impl(os, state.getImpl()).printType(*this);
3999 void Type::dump() const {
4000 print(llvm::errs());
4001 llvm::errs() << "\n";
4004 void AffineMap::dump() const {
4005 print(llvm::errs());
4006 llvm::errs() << "\n";
4009 void IntegerSet::dump() const {
4010 print(llvm::errs());
4011 llvm::errs() << "\n";
4014 void AffineExpr::print(raw_ostream &os) const {
4016 os << "<<NULL AFFINE EXPR>>";
4019 AsmState state(getContext());
4020 AsmPrinter::Impl(os, state.getImpl()).printAffineExpr(*this);
4023 void AffineExpr::dump() const {
4024 print(llvm::errs());
4025 llvm::errs() << "\n";
4028 void AffineMap::print(raw_ostream &os) const {
4030 os << "<<NULL AFFINE MAP>>";
4033 AsmState state(getContext());
4034 AsmPrinter::Impl(os, state.getImpl()).printAffineMap(*this);
4037 void IntegerSet::print(raw_ostream &os) const {
4038 AsmState state(getContext());
4039 AsmPrinter::Impl(os, state.getImpl()).printIntegerSet(*this);
4042 void Value::print(raw_ostream &os) const { print(os, OpPrintingFlags()); }
4043 void Value::print(raw_ostream &os, const OpPrintingFlags &flags) const {
4045 os << "<<NULL VALUE>>";
4049 if (auto *op = getDefiningOp())
4050 return op->print(os, flags);
4051 // TODO: Improve BlockArgument print'ing.
4053 os <<
"<block argument> of type '" << arg.
getType()
4058 os <<
"<<NULL VALUE>>";
4062 if (
auto *op = getDefiningOp())
4063 return op->
print(os, state);
4067 os <<
"<block argument> of type '" << arg.
getType()
4072 print(llvm::errs());
4073 llvm::errs() <<
"\n";
4081 state.getImpl().getSSANameState().printValueID(*
this,
true,
4104 if (
auto result = llvm::dyn_cast<OpResult>(*
this)) {
4107 op = llvm::cast<BlockArgument>(*this).getOwner()->
getParentOp();
4109 os <<
"<<UNKNOWN SSA VALUE>>";
4115 printAsOperand(os, state);
4125 OperationPrinter printer(os, state.getImpl());
4126 if (!getParent() && !state.getPrinterFlags().shouldUseLocalScope()) {
4127 state.getImpl().initializeAliases(
this);
4128 printer.printTopLevelOperation(
this);
4130 printer.printFullOpWithIndentAndLoc(
this);
4136 llvm::errs() <<
"\n";
4141 llvm::errs() <<
"\n";
4147 os <<
"<<UNLINKED BLOCK>>\n";
4158 OperationPrinter(os, state.getImpl()).print(
this);
4167 os <<
"<<UNLINKED BLOCK>>\n";
4171 printAsOperand(os, state);
4174 OperationPrinter printer(os, state.getImpl());
4175 printer.printBlockName(
this);
4190 if (dimensions.empty())
4193 if (dimensions.empty())
4203 <<
"Failed parsing dimension list.";
4214 <<
"Failed parsing dimension list.";
4216 if (shapeArr.empty()) {
4218 <<
"Failed parsing dimension list. Did you mean an empty list? It "
4219 "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::@1241::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.
virtual void printNamedAttribute(NamedAttribute attr)
Print the given named attribute.
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.
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.
void print(raw_ostream &os, const OpPrintingFlags &flags={})
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.