31 #include "llvm/ADT/APFloat.h"
32 #include "llvm/ADT/ArrayRef.h"
33 #include "llvm/ADT/DenseMap.h"
34 #include "llvm/ADT/MapVector.h"
35 #include "llvm/ADT/STLExtras.h"
36 #include "llvm/ADT/ScopeExit.h"
37 #include "llvm/ADT/ScopedHashTable.h"
38 #include "llvm/ADT/SetVector.h"
39 #include "llvm/ADT/SmallString.h"
40 #include "llvm/ADT/StringExtras.h"
41 #include "llvm/ADT/StringSet.h"
42 #include "llvm/ADT/TypeSwitch.h"
43 #include "llvm/Support/CommandLine.h"
44 #include "llvm/Support/Debug.h"
45 #include "llvm/Support/Endian.h"
46 #include "llvm/Support/ManagedStatic.h"
47 #include "llvm/Support/Regex.h"
48 #include "llvm/Support/SaveAndRestore.h"
49 #include "llvm/Support/Threading.h"
50 #include "llvm/Support/raw_ostream.h"
51 #include <type_traits>
59 #define DEBUG_TYPE "mlir-asm-printer"
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/OpAsmInterface.cpp.inc"
131 return entry.
emitError() <<
"unknown 'resource' key '" << entry.
getKey()
132 <<
"' for dialect '" << getDialect()->getNamespace()
144 struct AsmPrinterOptions {
145 llvm::cl::opt<int64_t> printElementsAttrWithHexIfLarger{
146 "mlir-print-elementsattrs-with-hex-if-larger",
148 "Print DenseElementsAttrs with a hex string that have "
149 "more elements than the given upper limit (use -1 to disable)")};
151 llvm::cl::opt<unsigned> elideElementsAttrIfLarger{
152 "mlir-elide-elementsattrs-if-larger",
153 llvm::cl::desc(
"Elide ElementsAttrs with \"...\" that have "
154 "more elements than the given upper limit")};
156 llvm::cl::opt<unsigned> elideResourceStringsIfLarger{
157 "mlir-elide-resource-strings-if-larger",
159 "Elide printing value of resources if string is too long in chars.")};
161 llvm::cl::opt<bool> printDebugInfoOpt{
162 "mlir-print-debuginfo", llvm::cl::init(
false),
163 llvm::cl::desc(
"Print debug info in MLIR output")};
165 llvm::cl::opt<bool> printPrettyDebugInfoOpt{
166 "mlir-pretty-debuginfo", llvm::cl::init(
false),
167 llvm::cl::desc(
"Print pretty debug info in MLIR output")};
171 llvm::cl::opt<bool> printGenericOpFormOpt{
172 "mlir-print-op-generic", llvm::cl::init(
false),
173 llvm::cl::desc(
"Print the generic op form"), llvm::cl::Hidden};
175 llvm::cl::opt<bool> assumeVerifiedOpt{
176 "mlir-print-assume-verified", llvm::cl::init(
false),
177 llvm::cl::desc(
"Skip op verification when using custom printers"),
180 llvm::cl::opt<bool> printLocalScopeOpt{
181 "mlir-print-local-scope", llvm::cl::init(
false),
182 llvm::cl::desc(
"Print with local scope and inline information (eliding "
183 "aliases for attributes, types, and locations")};
185 llvm::cl::opt<bool> skipRegionsOpt{
186 "mlir-print-skip-regions", llvm::cl::init(
false),
187 llvm::cl::desc(
"Skip regions when printing ops.")};
189 llvm::cl::opt<bool> printValueUsers{
190 "mlir-print-value-users", llvm::cl::init(
false),
192 "Print users of operation results and block arguments as a comment")};
194 llvm::cl::opt<bool> printUniqueSSAIDs{
195 "mlir-print-unique-ssa-ids", llvm::cl::init(
false),
196 llvm::cl::desc(
"Print unique SSA ID numbers for values, block arguments "
197 "and naming conflicts across all regions")};
201 static llvm::ManagedStatic<AsmPrinterOptions>
clOptions;
212 : printDebugInfoFlag(false), printDebugInfoPrettyFormFlag(false),
213 printGenericOpFormFlag(false), skipRegionsFlag(false),
214 assumeVerifiedFlag(false), printLocalScope(false),
215 printValueUsersFlag(false), printUniqueSSAIDsFlag(false) {
219 if (
clOptions->elideElementsAttrIfLarger.getNumOccurrences())
220 elementsAttrElementLimit =
clOptions->elideElementsAttrIfLarger;
221 if (
clOptions->printElementsAttrWithHexIfLarger.getNumOccurrences())
222 elementsAttrHexElementLimit =
223 clOptions->printElementsAttrWithHexIfLarger.getValue();
224 if (
clOptions->elideResourceStringsIfLarger.getNumOccurrences())
225 resourceStringCharLimit =
clOptions->elideResourceStringsIfLarger;
226 printDebugInfoFlag =
clOptions->printDebugInfoOpt;
227 printDebugInfoPrettyFormFlag =
clOptions->printPrettyDebugInfoOpt;
228 printGenericOpFormFlag =
clOptions->printGenericOpFormOpt;
229 assumeVerifiedFlag =
clOptions->assumeVerifiedOpt;
230 printLocalScope =
clOptions->printLocalScopeOpt;
231 skipRegionsFlag =
clOptions->skipRegionsOpt;
232 printValueUsersFlag =
clOptions->printValueUsers;
233 printUniqueSSAIDsFlag =
clOptions->printUniqueSSAIDs;
242 elementsAttrElementLimit = largeElementLimit;
248 elementsAttrHexElementLimit = largeElementLimit;
254 resourceStringCharLimit = largeResourceLimit;
262 printDebugInfoFlag = enable;
263 printDebugInfoPrettyFormFlag = prettyForm;
269 printGenericOpFormFlag = enable;
275 skipRegionsFlag = skip;
281 assumeVerifiedFlag =
true;
289 printLocalScope =
true;
295 printValueUsersFlag =
true;
301 return elementsAttrElementLimit &&
302 *elementsAttrElementLimit < int64_t(attr.getNumElements()) &&
303 !llvm::isa<SplatElementsAttr>(attr);
309 return (elementsAttrHexElementLimit != -1) &&
310 (elementsAttrHexElementLimit < int64_t(attr.getNumElements())) &&
311 !llvm::isa<SplatElementsAttr>(attr);
316 return elementsAttrElementLimit;
321 return elementsAttrHexElementLimit;
326 return resourceStringCharLimit;
331 return printDebugInfoFlag;
336 return printDebugInfoPrettyFormFlag;
341 return printGenericOpFormFlag;
349 return assumeVerifiedFlag;
357 return printValueUsersFlag;
373 struct NewLineCounter {
374 unsigned curLine = 1;
377 static raw_ostream &
operator<<(raw_ostream &os, NewLineCounter &newLine) {
396 template <
typename Container,
typename UnaryFunctor>
398 llvm::interleaveComma(c,
os, eachFn);
444 function_ref<
void(
unsigned,
bool)> printValueName =
nullptr);
457 bool withKeyword =
false);
461 bool isTopLevel =
false);
497 function_ref<
void(
unsigned,
bool)> printValueName =
nullptr);
521 SymbolAlias(StringRef name, uint32_t suffixIndex,
bool isType,
523 : name(name), suffixIndex(suffixIndex), isType(isType),
524 isDeferrable(isDeferrable) {}
527 void print(raw_ostream &os)
const {
528 os << (isType ?
"!" :
"#") << name;
534 bool isTypeAlias()
const {
return isType; }
537 bool canBeDeferred()
const {
return isDeferrable; }
543 uint32_t suffixIndex : 30;
547 bool isDeferrable : 1;
553 class AliasInitializer {
557 llvm::BumpPtrAllocator &aliasAllocator)
558 : interfaces(interfaces), aliasAllocator(aliasAllocator),
559 aliasOS(aliasBuffer) {}
562 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias);
570 std::pair<size_t, size_t>
visit(
Attribute attr,
bool canBeDeferred =
false,
571 bool elideType =
false) {
572 return visitImpl(attr, aliases, canBeDeferred, elideType);
579 std::pair<size_t, size_t>
visit(
Type type,
bool canBeDeferred =
false) {
580 return visitImpl(type, aliases, canBeDeferred);
584 struct InProgressAliasInfo {
585 InProgressAliasInfo()
586 : aliasDepth(0), isType(false), canBeDeferred(false) {}
587 InProgressAliasInfo(StringRef alias)
588 : alias(alias), aliasDepth(1), isType(false), canBeDeferred(false) {}
590 bool operator<(
const InProgressAliasInfo &rhs)
const {
592 if (aliasDepth != rhs.aliasDepth)
593 return aliasDepth < rhs.aliasDepth;
594 if (isType != rhs.isType)
596 return alias < rhs.alias;
601 std::optional<StringRef> alias;
604 unsigned aliasDepth : 30;
608 bool canBeDeferred : 1;
618 template <
typename T,
typename... PrintArgs>
619 std::pair<size_t, size_t>
621 llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
622 bool canBeDeferred, PrintArgs &&...printArgs);
625 void markAliasNonDeferrable(
size_t aliasIndex);
629 template <
typename T>
630 void generateAlias(T symbol, InProgressAliasInfo &alias,
bool canBeDeferred);
634 static void initializeAliases(
635 llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
636 llvm::MapVector<const void *, SymbolAlias> &symbolToAlias);
642 llvm::BumpPtrAllocator &aliasAllocator;
645 llvm::MapVector<const void *, InProgressAliasInfo> aliases;
649 llvm::raw_svector_ostream aliasOS;
657 class DummyAliasOperationPrinter :
private OpAsmPrinter {
659 explicit DummyAliasOperationPrinter(
const OpPrintingFlags &printerFlags,
660 AliasInitializer &initializer)
661 : printerFlags(printerFlags), initializer(initializer) {}
665 void printCustomOrGenericOp(
Operation *op)
override {
667 if (printerFlags.shouldPrintDebugInfo())
668 initializer.visit(op->
getLoc(),
true);
671 if (!printerFlags.shouldPrintGenericOpForm()) {
682 void printGenericOp(
Operation *op,
bool printOpName =
true)
override {
684 if (!printerFlags.shouldSkipRegions()) {
698 printAttribute(attr.getValue());
704 void print(
Block *block,
bool printBlockArgs =
true,
705 bool printBlockTerminator =
true) {
708 if (printBlockArgs) {
713 if (printerFlags.shouldPrintDebugInfo())
715 initializer.visit(arg.getLoc(),
false);
723 auto range = llvm::make_range(
725 std::prev(block->
end(),
726 (!hasTerminator || printBlockTerminator) ? 0 : 1));
728 printCustomOrGenericOp(&op);
733 bool printBlockTerminators,
734 bool printEmptyBlock =
false)
override {
737 if (printerFlags.shouldSkipRegions()) {
742 auto *entryBlock = ®ion.
front();
743 print(entryBlock, printEntryBlockArgs, printBlockTerminators);
744 for (
Block &b : llvm::drop_begin(region, 1))
749 bool omitType)
override {
752 if (printerFlags.shouldPrintDebugInfo())
754 initializer.visit(arg.
getLoc(),
false);
758 void printType(
Type type)
override { initializer.visit(type); }
761 void printAttribute(
Attribute attr)
override { initializer.visit(attr); }
762 void printAttributeWithoutType(
Attribute attr)
override {
763 printAttribute(attr);
765 LogicalResult printAlias(
Attribute attr)
override {
766 initializer.visit(attr);
769 LogicalResult printAlias(
Type type)
override {
770 initializer.visit(type);
775 void printOptionalLocationSpecifier(
Location loc)
override {
785 if (elidedAttrs.empty()) {
787 printAttribute(attr.getValue());
790 llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
793 if (!elidedAttrsSet.contains(attr.getName().strref()))
794 printAttribute(attr.getValue());
796 void printOptionalAttrDictWithKeyword(
799 printOptionalAttrDict(attrs, elidedAttrs);
804 raw_ostream &getStream()
const override {
return os; }
808 void printFloat(
const APFloat &)
override {}
809 void printAffineMapOfSSAIds(AffineMapAttr,
ValueRange)
override {}
812 void increaseIndent()
override {}
813 void decreaseIndent()
override {}
814 void printOperand(
Value)
override {}
815 void printOperand(
Value, raw_ostream &os)
override {
824 void printSymbolName(StringRef)
override {}
825 void printSuccessor(
Block *)
override {}
833 AliasInitializer &initializer;
836 mutable llvm::raw_null_ostream os;
841 explicit DummyAliasDialectAsmPrinter(AliasInitializer &initializer,
844 : initializer(initializer), canBeDeferred(canBeDeferred),
845 childIndices(childIndices) {}
850 template <
typename T,
typename... PrintArgs>
851 size_t printAndVisitNestedAliases(T value, PrintArgs &&...printArgs) {
852 printAndVisitNestedAliasesImpl(value, printArgs...);
853 return maxAliasDepth;
859 void printAndVisitNestedAliasesImpl(
Attribute attr,
bool elideType) {
860 if (!isa<BuiltinDialect>(attr.
getDialect())) {
864 }
else if (llvm::isa<AffineMapAttr, DenseArrayAttr, FloatAttr, IntegerAttr,
865 IntegerSetAttr, UnitAttr>(attr)) {
867 }
else if (
auto distinctAttr = dyn_cast<DistinctAttr>(attr)) {
868 printAttribute(distinctAttr.getReferencedAttr());
869 }
else if (
auto dictAttr = dyn_cast<DictionaryAttr>(attr)) {
871 printAttribute(nestedAttr.getName());
872 printAttribute(nestedAttr.getValue());
874 }
else if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr)) {
875 for (
Attribute nestedAttr : arrayAttr.getValue())
876 printAttribute(nestedAttr);
877 }
else if (
auto typeAttr = dyn_cast<TypeAttr>(attr)) {
879 }
else if (
auto locAttr = dyn_cast<OpaqueLoc>(attr)) {
880 printAttribute(locAttr.getFallbackLocation());
881 }
else if (
auto locAttr = dyn_cast<NameLoc>(attr)) {
882 if (!isa<UnknownLoc>(locAttr.getChildLoc()))
883 printAttribute(locAttr.getChildLoc());
884 }
else if (
auto locAttr = dyn_cast<CallSiteLoc>(attr)) {
885 printAttribute(locAttr.getCallee());
886 printAttribute(locAttr.getCaller());
887 }
else if (
auto locAttr = dyn_cast<FusedLoc>(attr)) {
888 if (
Attribute metadata = locAttr.getMetadata())
889 printAttribute(metadata);
890 for (
Location nestedLoc : locAttr.getLocations())
891 printAttribute(nestedLoc);
896 if (
auto typedAttr = llvm::dyn_cast<TypedAttr>(attr)) {
897 Type attrType = typedAttr.getType();
898 if (!llvm::isa<NoneType>(attrType))
903 void printAndVisitNestedAliasesImpl(
Type type) {
908 if (
auto memrefTy = llvm::dyn_cast<MemRefType>(type)) {
910 MemRefLayoutAttrInterface layout = memrefTy.getLayout();
911 if (!llvm::isa<AffineMapAttr>(layout) || !layout.isIdentity())
912 printAttribute(memrefTy.getLayout());
913 if (memrefTy.getMemorySpace())
914 printAttribute(memrefTy.getMemorySpace());
919 auto visitFn = [&](
auto element) {
921 (void)printAlias(element);
928 recordAliasResult(initializer.visit(type, canBeDeferred));
932 void printAttribute(
Attribute attr)
override {
933 recordAliasResult(initializer.visit(attr, canBeDeferred));
935 void printAttributeWithoutType(
Attribute attr)
override {
937 initializer.visit(attr, canBeDeferred,
true));
939 LogicalResult printAlias(
Attribute attr)
override {
940 printAttribute(attr);
943 LogicalResult printAlias(
Type type)
override {
949 void recordAliasResult(std::pair<size_t, size_t> aliasDepthAndIndex) {
950 childIndices.push_back(aliasDepthAndIndex.second);
951 if (aliasDepthAndIndex.first > maxAliasDepth)
952 maxAliasDepth = aliasDepthAndIndex.first;
957 raw_ostream &getStream()
const override {
return os; }
961 void printFloat(
const APFloat &)
override {}
964 void printSymbolName(StringRef)
override {}
967 LogicalResult pushCyclicPrinting(
const void *opaquePointer)
override {
968 return success(cyclicPrintingStack.insert(opaquePointer));
971 void popCyclicPrinting()
override { cyclicPrintingStack.pop_back(); }
978 AliasInitializer &initializer;
987 size_t maxAliasDepth = 0;
990 mutable llvm::raw_null_ostream os;
998 StringRef allowedPunctChars =
"$._-",
999 bool allowTrailingDigit =
true) {
1000 assert(!name.empty() &&
"Shouldn't have an empty name here");
1002 auto validChar = [&](
char ch) {
1003 return llvm::isAlnum(ch) || allowedPunctChars.contains(ch);
1006 auto copyNameToBuffer = [&] {
1007 for (
char ch : name) {
1009 buffer.push_back(ch);
1011 buffer.push_back(
'_');
1013 buffer.append(llvm::utohexstr((
unsigned char)ch));
1020 if (isdigit(name[0]) || (!validChar(name[0]) && name[0] !=
' ')) {
1021 buffer.push_back(
'_');
1028 if (!allowTrailingDigit && isdigit(name.back())) {
1030 buffer.push_back(
'_');
1035 for (
char ch : name) {
1036 if (!validChar(ch)) {
1048 void AliasInitializer::initializeAliases(
1049 llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
1050 llvm::MapVector<const void *, SymbolAlias> &symbolToAlias) {
1052 unprocessedAliases = visitedSymbols.takeVector();
1053 llvm::stable_sort(unprocessedAliases, [](
const auto &lhs,
const auto &rhs) {
1054 return lhs.second < rhs.second;
1057 llvm::StringMap<unsigned> nameCounts;
1058 for (
auto &[symbol, aliasInfo] : unprocessedAliases) {
1059 if (!aliasInfo.alias)
1061 StringRef alias = *aliasInfo.alias;
1062 unsigned nameIndex = nameCounts[alias]++;
1063 symbolToAlias.insert(
1064 {symbol, SymbolAlias(alias, nameIndex, aliasInfo.isType,
1065 aliasInfo.canBeDeferred)});
1069 void AliasInitializer::initialize(
1071 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias) {
1075 DummyAliasOperationPrinter aliasPrinter(printerFlags, *
this);
1076 aliasPrinter.printCustomOrGenericOp(op);
1079 initializeAliases(aliases, attrTypeToAlias);
1082 template <
typename T,
typename... PrintArgs>
1083 std::pair<size_t, size_t> AliasInitializer::visitImpl(
1084 T value, llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
1085 bool canBeDeferred, PrintArgs &&...printArgs) {
1086 auto [it, inserted] =
1087 aliases.insert({value.getAsOpaquePointer(), InProgressAliasInfo()});
1088 size_t aliasIndex = std::distance(aliases.begin(), it);
1092 markAliasNonDeferrable(aliasIndex);
1093 return {
static_cast<size_t>(it->second.aliasDepth), aliasIndex};
1097 generateAlias(value, it->second, canBeDeferred);
1098 it->second.isType = std::is_base_of_v<Type, T>;
1099 it->second.canBeDeferred = canBeDeferred;
1103 DummyAliasDialectAsmPrinter printer(*
this, canBeDeferred, childAliases);
1104 size_t maxAliasDepth =
1105 printer.printAndVisitNestedAliases(value, printArgs...);
1108 it = std::next(aliases.begin(), aliasIndex);
1111 it->second.childIndices = std::move(childAliases);
1113 it->second.aliasDepth = maxAliasDepth + 1;
1116 return {(size_t)it->second.aliasDepth, aliasIndex};
1119 void AliasInitializer::markAliasNonDeferrable(
size_t aliasIndex) {
1120 auto *it = std::next(aliases.begin(), aliasIndex);
1124 if (!it->second.canBeDeferred)
1127 it->second.canBeDeferred =
false;
1130 for (
size_t childIndex : it->second.childIndices)
1131 markAliasNonDeferrable(childIndex);
1134 template <
typename T>
1135 void AliasInitializer::generateAlias(T symbol, InProgressAliasInfo &alias,
1136 bool canBeDeferred) {
1138 for (
const auto &interface : interfaces) {
1140 interface.getAlias(symbol, aliasOS);
1143 nameBuffer = std::move(aliasBuffer);
1144 assert(!nameBuffer.empty() &&
"expected valid alias name");
1149 if (nameBuffer.empty())
1156 name = name.copy(aliasAllocator);
1157 alias = InProgressAliasInfo(name);
1175 LogicalResult getAlias(
Attribute attr, raw_ostream &os)
const;
1179 LogicalResult getAlias(
Type ty, raw_ostream &os)
const;
1183 void printNonDeferredAliases(
AsmPrinter::Impl &p, NewLineCounter &newLine) {
1184 printAliases(p, newLine,
false);
1189 printAliases(p, newLine,
true);
1199 llvm::MapVector<const void *, SymbolAlias> attrTypeToAlias;
1202 llvm::BumpPtrAllocator aliasAllocator;
1206 void AliasState::initialize(
1209 AliasInitializer initializer(interfaces, aliasAllocator);
1210 initializer.initialize(op, printerFlags, attrTypeToAlias);
1213 LogicalResult AliasState::getAlias(
Attribute attr, raw_ostream &os)
const {
1215 if (it == attrTypeToAlias.end())
1217 it->second.print(os);
1221 LogicalResult AliasState::getAlias(
Type ty, raw_ostream &os)
const {
1223 if (it == attrTypeToAlias.end())
1226 it->second.print(os);
1230 void AliasState::printAliases(
AsmPrinter::Impl &p, NewLineCounter &newLine,
1232 auto filterFn = [=](
const auto &aliasIt) {
1233 return aliasIt.second.canBeDeferred() == isDeferred;
1235 for (
auto &[opaqueSymbol, alias] :
1236 llvm::make_filter_range(attrTypeToAlias, filterFn)) {
1240 if (alias.isTypeAlias()) {
1273 class SSANameState {
1276 enum :
unsigned { NameSentinel = ~0U };
1279 SSANameState() =
default;
1284 void printValueID(
Value value,
bool printResultNo, raw_ostream &stream)
const;
1287 void printOperationID(
Operation *op, raw_ostream &stream)
const;
1294 BlockInfo getBlockInfo(
Block *block);
1303 void numberValuesInRegion(
Region ®ion);
1304 void numberValuesInBlock(
Block &block);
1311 void getResultIDAndNumber(
OpResult result,
Value &lookupValue,
1312 std::optional<int> &lookupResultNo)
const;
1315 void setValueName(
Value value, StringRef name);
1319 StringRef uniqueValueName(StringRef name);
1342 llvm::ScopedHashTable<StringRef, char> usedNames;
1343 llvm::BumpPtrAllocator usedNameAllocator;
1346 unsigned nextValueID = 0;
1348 unsigned nextArgumentID = 0;
1350 unsigned nextConflictID = 0;
1359 : printerFlags(printerFlags) {
1360 llvm::SaveAndRestore valueIDSaver(nextValueID);
1361 llvm::SaveAndRestore argumentIDSaver(nextArgumentID);
1362 llvm::SaveAndRestore conflictIDSaver(nextConflictID);
1367 using UsedNamesScopeTy = llvm::ScopedHashTable<StringRef, char>::ScopeTy;
1368 using NamingContext =
1369 std::tuple<Region *, unsigned, unsigned, unsigned, UsedNamesScopeTy *>;
1372 llvm::BumpPtrAllocator allocator;
1375 auto *topLevelNamesScope =
1376 new (allocator.Allocate<UsedNamesScopeTy>()) UsedNamesScopeTy(usedNames);
1380 nameContext.push_back(std::make_tuple(®ion, nextValueID, nextArgumentID,
1381 nextConflictID, topLevelNamesScope));
1383 numberValuesInOp(*op);
1385 while (!nameContext.empty()) {
1387 UsedNamesScopeTy *parentScope;
1391 std::tie(region, std::ignore, std::ignore, std::ignore, parentScope) =
1392 nameContext.pop_back_val();
1394 std::tie(region, nextValueID, nextArgumentID, nextConflictID,
1395 parentScope) = nameContext.pop_back_val();
1399 while (usedNames.getCurScope() != parentScope) {
1400 usedNames.getCurScope()->~UsedNamesScopeTy();
1401 assert((usedNames.getCurScope() !=
nullptr || parentScope ==
nullptr) &&
1402 "top level parentScope must be a nullptr");
1406 auto *curNamesScope =
new (allocator.Allocate<UsedNamesScopeTy>())
1407 UsedNamesScopeTy(usedNames);
1409 numberValuesInRegion(*region);
1413 nameContext.push_back(std::make_tuple(®ion, nextValueID,
1414 nextArgumentID, nextConflictID,
1419 while (usedNames.getCurScope() !=
nullptr)
1420 usedNames.getCurScope()->~UsedNamesScopeTy();
1423 void SSANameState::printValueID(
Value value,
bool printResultNo,
1424 raw_ostream &stream)
const {
1426 stream <<
"<<NULL VALUE>>";
1430 std::optional<int> resultNo;
1431 auto lookupValue = value;
1435 if (
OpResult result = dyn_cast<OpResult>(value))
1436 getResultIDAndNumber(result, lookupValue, resultNo);
1438 auto it = valueIDs.find(lookupValue);
1439 if (it == valueIDs.end()) {
1440 stream <<
"<<UNKNOWN SSA VALUE>>";
1445 if (it->second != NameSentinel) {
1446 stream << it->second;
1448 auto nameIt = valueNames.find(lookupValue);
1449 assert(nameIt != valueNames.end() &&
"Didn't have a name entry?");
1450 stream << nameIt->second;
1453 if (resultNo && printResultNo)
1454 stream <<
'#' << *resultNo;
1457 void SSANameState::printOperationID(
Operation *op, raw_ostream &stream)
const {
1458 auto it = operationIDs.find(op);
1459 if (it == operationIDs.end()) {
1460 stream <<
"<<UNKNOWN OPERATION>>";
1462 stream <<
'%' << it->second;
1467 auto it = opResultGroups.find(op);
1468 return it == opResultGroups.end() ?
ArrayRef<int>() : it->second;
1471 BlockInfo SSANameState::getBlockInfo(
Block *block) {
1472 auto it = blockNames.find(block);
1473 BlockInfo invalidBlock{-1,
"INVALIDBLOCK"};
1474 return it != blockNames.end() ? it->second : invalidBlock;
1477 void SSANameState::shadowRegionArgs(
Region ®ion,
ValueRange namesToUse) {
1478 assert(!region.
empty() &&
"cannot shadow arguments of an empty region");
1480 "incorrect number of names passed in");
1482 "only KnownIsolatedFromAbove ops can shadow names");
1485 for (
unsigned i = 0, e = namesToUse.size(); i != e; ++i) {
1486 auto nameToUse = namesToUse[i];
1487 if (nameToUse ==
nullptr)
1492 llvm::raw_svector_ostream nameStream(nameStr);
1493 printValueID(nameToUse,
true, nameStream);
1496 assert(valueIDs[nameToReplace] == NameSentinel);
1499 auto name = StringRef(nameStream.str()).drop_front();
1502 valueNames[nameToReplace] = name.copy(usedNameAllocator);
1506 void SSANameState::numberValuesInRegion(
Region ®ion) {
1507 auto setBlockArgNameFn = [&](
Value arg, StringRef name) {
1508 assert(!valueIDs.count(arg) &&
"arg numbered multiple times");
1509 assert(llvm::cast<BlockArgument>(arg).getOwner()->getParent() == ®ion &&
1510 "arg not defined in current region");
1511 setValueName(arg, name);
1516 if (
auto asmInterface = dyn_cast<OpAsmOpInterface>(op))
1517 asmInterface.getAsmBlockArgumentNames(region, setBlockArgNameFn);
1522 unsigned nextBlockID = 0;
1523 for (
auto &block : region) {
1526 auto blockInfoIt = blockNames.insert({&block, {-1,
""}});
1527 if (blockInfoIt.second) {
1531 llvm::raw_string_ostream(name) <<
"^bb" << nextBlockID;
1532 blockInfoIt.first->second.name = StringRef(name).copy(usedNameAllocator);
1534 blockInfoIt.first->second.ordering = nextBlockID++;
1536 numberValuesInBlock(block);
1540 void SSANameState::numberValuesInBlock(
Block &block) {
1545 llvm::raw_svector_ostream specialName(specialNameBuffer);
1547 if (valueIDs.count(arg))
1550 specialNameBuffer.resize(strlen(
"arg"));
1551 specialName << nextArgumentID++;
1553 setValueName(arg, specialName.str());
1557 for (
auto &op : block)
1558 numberValuesInOp(op);
1561 void SSANameState::numberValuesInOp(
Operation &op) {
1564 auto setResultNameFn = [&](
Value result, StringRef name) {
1565 assert(!valueIDs.count(result) &&
"result numbered multiple times");
1566 assert(result.
getDefiningOp() == &op &&
"result not defined by 'op'");
1567 setValueName(result, name);
1570 if (
int resultNo = llvm::cast<OpResult>(result).getResultNumber())
1571 resultGroups.push_back(resultNo);
1574 auto setBlockNameFn = [&](
Block *block, StringRef name) {
1576 "getAsmBlockArgumentNames callback invoked on a block not directly "
1577 "nested under the current operation");
1578 assert(!blockNames.count(block) &&
"block numbered multiple times");
1581 if (name.data() != tmpBuffer.data()) {
1582 tmpBuffer.append(name);
1583 name = tmpBuffer.str();
1585 name = name.copy(usedNameAllocator);
1586 blockNames[block] = {-1, name};
1590 if (OpAsmOpInterface asmInterface = dyn_cast<OpAsmOpInterface>(&op)) {
1591 asmInterface.getAsmBlockNames(setBlockNameFn);
1592 asmInterface.getAsmResultNames(setResultNameFn);
1597 if (numResults == 0) {
1600 if (operationIDs.try_emplace(&op, nextValueID).second)
1608 if (valueIDs.try_emplace(resultBegin, nextValueID).second)
1612 if (resultGroups.size() != 1) {
1613 llvm::array_pod_sort(resultGroups.begin(), resultGroups.end());
1614 opResultGroups.try_emplace(&op, std::move(resultGroups));
1618 void SSANameState::getResultIDAndNumber(
1620 std::optional<int> &lookupResultNo)
const {
1628 auto resultGroupIt = opResultGroups.find(owner);
1629 if (resultGroupIt == opResultGroups.end()) {
1631 lookupResultNo = resultNo;
1638 const auto *it = llvm::upper_bound(resultGroups, resultNo);
1639 int groupResultNo = 0, groupSize = 0;
1642 if (it == resultGroups.end()) {
1643 groupResultNo = resultGroups.back();
1644 groupSize =
static_cast<int>(owner->
getNumResults()) - resultGroups.back();
1647 groupResultNo = *std::prev(it);
1648 groupSize = *it - groupResultNo;
1653 lookupResultNo = resultNo - groupResultNo;
1654 lookupValue = owner->
getResult(groupResultNo);
1657 void SSANameState::setValueName(
Value value, StringRef name) {
1660 valueIDs[value] = nextValueID++;
1664 valueIDs[value] = NameSentinel;
1665 valueNames[value] = uniqueValueName(name);
1668 StringRef SSANameState::uniqueValueName(StringRef name) {
1673 if (!usedNames.count(name)) {
1674 name = name.copy(usedNameAllocator);
1680 probeName.push_back(
'_');
1682 probeName += llvm::utostr(nextConflictID++);
1683 if (!usedNames.count(probeName)) {
1684 name = probeName.str().copy(usedNameAllocator);
1687 probeName.resize(name.size() + 1);
1691 usedNames.insert(name,
char());
1701 class DistinctState {
1707 uint64_t distinctCounter = 0;
1712 uint64_t DistinctState::getId(
DistinctAttr distinctAttr) {
1713 auto [it, inserted] =
1714 distinctAttrMap.try_emplace(distinctAttr, distinctCounter);
1717 return it->getSecond();
1724 AsmParsedResourceEntry::~AsmParsedResourceEntry() =
default;
1725 AsmResourceBuilder::~AsmResourceBuilder() =
default;
1726 AsmResourceParser::~AsmResourceParser() =
default;
1727 AsmResourcePrinter::~AsmResourcePrinter() =
default;
1731 case AsmResourceEntryKind::Blob:
1733 case AsmResourceEntryKind::Bool:
1735 case AsmResourceEntryKind::String:
1738 llvm_unreachable(
"unknown AsmResourceEntryKind");
1742 std::unique_ptr<ResourceCollection> &collection = keyToResources[key.str()];
1744 collection = std::make_unique<ResourceCollection>(key);
1748 std::vector<std::unique_ptr<AsmResourcePrinter>>
1750 std::vector<std::unique_ptr<AsmResourcePrinter>> printers;
1751 for (
auto &it : keyToResources) {
1752 ResourceCollection *collection = it.second.get();
1754 return collection->buildResources(op, builder);
1756 printers.emplace_back(
1762 LogicalResult FallbackAsmResourceMap::ResourceCollection::parseResource(
1766 FailureOr<AsmResourceBlob> blob = entry.
parseAsBlob();
1769 resources.emplace_back(entry.
getKey(), std::move(*blob));
1776 resources.emplace_back(entry.
getKey(), *value);
1783 resources.emplace_back(entry.
getKey(), std::move(*str));
1790 void FallbackAsmResourceMap::ResourceCollection::buildResources(
1792 for (
const auto &entry : resources) {
1793 if (
const auto *value = std::get_if<AsmResourceBlob>(&entry.value))
1795 else if (
const auto *value = std::get_if<bool>(&entry.value))
1797 else if (
const auto *value = std::get_if<std::string>(&entry.value))
1800 llvm_unreachable(
"unknown AsmResourceEntryKind");
1814 : interfaces(op->
getContext()), nameState(op, printerFlags),
1815 printerFlags(printerFlags), locationMap(locationMap) {}
1818 : interfaces(ctx), printerFlags(printerFlags), locationMap(locationMap) {}
1822 aliasState.initialize(op, printerFlags, interfaces);
1842 return llvm::make_pointee_range(externalResourcePrinters);
1852 (*locationMap)[op] = std::make_pair(line, col);
1858 return dialectResources;
1862 return success(cyclicPrintingStack.insert(opaquePointer));
1878 AliasState aliasState;
1881 SSANameState nameState;
1884 DistinctState distinctState;
1900 template <
typename Range>
1904 [&stream](
const auto &dimSize) {
1905 if (ShapedType::isDynamic(dimSize))
1923 return printerFlags;
1927 auto parentThreadId = llvm::get_threadid();
1929 if (parentThreadId == llvm::get_threadid()) {
1931 diag.print(llvm::dbgs());
1932 llvm::dbgs() <<
"\n";
1938 if (failed(
verify(op))) {
1939 LLVM_DEBUG(llvm::dbgs()
1941 <<
"' failed to verify and will be printed in generic form\n");
1945 return printerFlags;
1964 return impl->getPrinterFlags();
1968 std::unique_ptr<AsmResourcePrinter> printer) {
1969 impl->externalResourcePrinters.emplace_back(std::move(printer));
1974 return impl->getDialectResources();
1982 : os(os), state(state), printerFlags(state.getPrinterFlags()) {}
1990 printLocation(loc, allowAlias);
1996 if (!isTopLevel && succeeded(state.getAliasState().getAlias(loc, os)))
2000 .Case<OpaqueLoc>([&](OpaqueLoc loc) {
2001 printLocationInternal(loc.getFallbackLocation(), pretty);
2003 .Case<UnknownLoc>([&](UnknownLoc loc) {
2009 .Case<FileLineColLoc>([&](FileLineColLoc loc) {
2011 os << loc.getFilename().getValue();
2013 printEscapedString(loc.getFilename());
2014 os <<
':' << loc.getLine() <<
':' << loc.getColumn();
2016 .Case<NameLoc>([&](NameLoc loc) {
2017 printEscapedString(loc.getName());
2020 auto childLoc = loc.getChildLoc();
2021 if (!llvm::isa<UnknownLoc>(childLoc)) {
2023 printLocationInternal(childLoc, pretty);
2027 .Case<CallSiteLoc>([&](CallSiteLoc loc) {
2032 printLocationInternal(callee, pretty);
2034 if (llvm::isa<NameLoc>(callee)) {
2035 if (llvm::isa<FileLineColLoc>(caller)) {
2038 os << newLine <<
" at ";
2041 os << newLine <<
" at ";
2046 printLocationInternal(caller, pretty);
2050 .Case<FusedLoc>([&](
FusedLoc loc) {
2053 if (
Attribute metadata = loc.getMetadata()) {
2061 [&](Location loc) { printLocationInternal(loc, pretty); },
2062 [&]() { os << ", "; });
2069 static void printFloatValue(const APFloat &apValue, raw_ostream &os,
2070 bool *printedHex = nullptr) {
2071 // We would like to output the FP constant value in exponential notation,
2072 // but we cannot do this if doing so will lose precision. Check here to
2073 // make sure that we only output it in exponential format if we can parse
2074 // the value back and get the same value.
2075 bool isInf = apValue.isInfinity();
2076 bool isNaN = apValue.isNaN();
2077 if (!isInf && !isNaN) {
2078 SmallString<128> strValue;
2079 apValue.toString(strValue, /*FormatPrecision=*/6, /*FormatMaxPadding=*/0,
2080 /*TruncateZero=*/false);
2082 // Check to make sure that the stringized number is not some string like
2083 // "Inf" or NaN, that atof will accept, but the lexer will not. Check
2084 // that the string matches the "[-+]?[0-9]" regex.
2085 assert(((strValue[0] >= '0
' && strValue[0] <= '9') ||
2086 ((strValue[0] ==
'-' || strValue[0] ==
'+') &&
2087 (strValue[1] >=
'0' && strValue[1] <=
'9'))) &&
2088 "[-+]?[0-9] regex does not match!");
2092 if (APFloat(apValue.getSemantics(), strValue).bitwiseIsEqual(apValue)) {
2100 apValue.toString(strValue);
2103 if (strValue.str().contains(
'.')) {
2114 APInt apInt = apValue.bitcastToAPInt();
2115 apInt.toString(str, 16,
false,
2122 return printLocationInternal(loc,
true,
true);
2126 printLocationInternal(loc,
false,
true);
2134 state.getDialectResources()[resource.
getDialect()].insert(resource);
2142 if (symName.empty() || !isalpha(symName.front()))
2147 symName = symName.drop_while(
2148 [](
char c) {
return llvm::isAlnum(c) || c ==
'.' || c ==
'_'; });
2149 if (symName.empty())
2154 return symName.front() ==
'<' && symName.back() ==
'>';
2159 StringRef dialectName, StringRef symString) {
2160 os << symPrefix << dialectName;
2165 os <<
'.' << symString;
2169 os << '<' << symString << '>
';
2173 static bool isBareIdentifier(StringRef name) {
2174 // By making this unsigned, the value passed in to isalnum will always be
2175 // in the range 0-255. This is important when building with MSVC because
2176 // its implementation will assert. This situation can arise when dealing
2177 // with UTF-8 multibyte characters.
2178 if (name.empty() || (!isalpha(name[0]) && name[0] != '_
'))
2180 return llvm::all_of(name.drop_front(), [](unsigned char c) {
2181 return isalnum(c) || c == '_
' || c == '$
' || c == '.
';
2187 static void printKeywordOrString(StringRef keyword, raw_ostream &os) {
2188 // If it can be represented as a bare identifier, write it directly.
2189 if (isBareIdentifier(keyword)) {
2194 // Otherwise, output the keyword wrapped in quotes with proper escaping.
2196 printEscapedString(keyword, os);
2203 static void printSymbolReference(StringRef symbolRef, raw_ostream &os) {
2204 if (symbolRef.empty()) {
2205 os << "@<<INVALID EMPTY SYMBOL>>
";
2209 printKeywordOrString(symbolRef, os);
2212 // Print out a valid ElementsAttr that is succinct and can represent any
2213 // potential shape/type, for use when eliding a large ElementsAttr.
2215 // We choose to use a dense resource ElementsAttr literal with conspicuous
2216 // content to hopefully alert readers to the fact that this has been elided.
2217 static void printElidedElementsAttr(raw_ostream &os) {
2218 os << R"(dense_resource<__elided__>)
";
2221 LogicalResult AsmPrinter::Impl::printAlias(Attribute attr) {
2222 return state.getAliasState().getAlias(attr, os);
2225 LogicalResult AsmPrinter::Impl::printAlias(Type type) {
2226 return state.getAliasState().getAlias(type, os);
2229 void AsmPrinter::Impl::printAttribute(Attribute attr,
2230 AttrTypeElision typeElision) {
2232 os << "<<NULL ATTRIBUTE>>
";
2236 // Try to print an alias for this attribute.
2237 if (succeeded(printAlias(attr)))
2239 return printAttributeImpl(attr, typeElision);
2242 void AsmPrinter::Impl::printAttributeImpl(Attribute attr,
2243 AttrTypeElision typeElision) {
2244 if (!isa<BuiltinDialect>(attr.getDialect())) {
2245 printDialectAttribute(attr);
2246 } else if (auto opaqueAttr = llvm::dyn_cast<OpaqueAttr>(attr)) {
2247 printDialectSymbol(os, "#
", opaqueAttr.getDialectNamespace(),
2248 opaqueAttr.getAttrData());
2249 } else if (llvm::isa<UnitAttr>(attr)) {
2252 } else if (auto distinctAttr = llvm::dyn_cast<DistinctAttr>(attr)) {
2253 os << "distinct[
" << state.getDistinctState().getId(distinctAttr) << "]<
";
2254 if (!llvm::isa<UnitAttr>(distinctAttr.getReferencedAttr())) {
2255 printAttribute(distinctAttr.getReferencedAttr());
2259 } else if (auto dictAttr = llvm::dyn_cast<DictionaryAttr>(attr)) {
2261 interleaveComma(dictAttr.getValue(),
2262 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2265 } else if (auto intAttr = llvm::dyn_cast<IntegerAttr>(attr)) {
2266 Type intType = intAttr.getType();
2267 if (intType.isSignlessInteger(1)) {
2268 os << (intAttr.getValue().getBoolValue() ? "true" : "false");
2270 // Boolean integer attributes always elides the type.
2274 // Only print attributes as unsigned if they are explicitly unsigned or are
2275 // signless 1-bit values. Indexes, signed values, and multi-bit signless
2276 // values print as signed.
2278 intType.isUnsignedInteger() || intType.isSignlessInteger(1);
2279 intAttr.getValue().print(os, !isUnsigned);
2281 // IntegerAttr elides the type if I64.
2282 if (typeElision == AttrTypeElision::May && intType.isSignlessInteger(64))
2285 } else if (auto floatAttr = llvm::dyn_cast<FloatAttr>(attr)) {
2286 bool printedHex = false;
2287 printFloatValue(floatAttr.getValue(), os, &printedHex);
2289 // FloatAttr elides the type if F64.
2290 if (typeElision == AttrTypeElision::May && floatAttr.getType().isF64() &&
2294 } else if (auto strAttr = llvm::dyn_cast<StringAttr>(attr)) {
2295 printEscapedString(strAttr.getValue());
2297 } else if (auto arrayAttr = llvm::dyn_cast<ArrayAttr>(attr)) {
2299 interleaveComma(arrayAttr.getValue(), [&](Attribute attr) {
2300 printAttribute(attr, AttrTypeElision::May);
2304 } else if (auto affineMapAttr = llvm::dyn_cast<AffineMapAttr>(attr)) {
2305 os << "affine_map<
";
2306 affineMapAttr.getValue().print(os);
2309 // AffineMap always elides the type.
2312 } else if (auto integerSetAttr = llvm::dyn_cast<IntegerSetAttr>(attr)) {
2313 os << "affine_set<
";
2314 integerSetAttr.getValue().print(os);
2317 // IntegerSet always elides the type.
2320 } else if (auto typeAttr = llvm::dyn_cast<TypeAttr>(attr)) {
2321 printType(typeAttr.getValue());
2323 } else if (auto refAttr = llvm::dyn_cast<SymbolRefAttr>(attr)) {
2324 printSymbolReference(refAttr.getRootReference().getValue(), os);
2325 for (FlatSymbolRefAttr nestedRef : refAttr.getNestedReferences()) {
2327 printSymbolReference(nestedRef.getValue(), os);
2330 } else if (auto intOrFpEltAttr =
2331 llvm::dyn_cast<DenseIntOrFPElementsAttr>(attr)) {
2332 if (printerFlags.shouldElideElementsAttr(intOrFpEltAttr)) {
2333 printElidedElementsAttr(os);
2336 printDenseIntOrFPElementsAttr(intOrFpEltAttr, /*allowHex=*/true);
2340 } else if (auto strEltAttr = llvm::dyn_cast<DenseStringElementsAttr>(attr)) {
2341 if (printerFlags.shouldElideElementsAttr(strEltAttr)) {
2342 printElidedElementsAttr(os);
2345 printDenseStringElementsAttr(strEltAttr);
2349 } else if (auto sparseEltAttr = llvm::dyn_cast<SparseElementsAttr>(attr)) {
2350 if (printerFlags.shouldElideElementsAttr(sparseEltAttr.getIndices()) ||
2351 printerFlags.shouldElideElementsAttr(sparseEltAttr.getValues())) {
2352 printElidedElementsAttr(os);
2355 DenseIntElementsAttr indices = sparseEltAttr.getIndices();
2356 if (indices.getNumElements() != 0) {
2357 printDenseIntOrFPElementsAttr(indices, /*allowHex=*/false);
2359 printDenseElementsAttr(sparseEltAttr.getValues(), /*allowHex=*/true);
2363 } else if (auto stridedLayoutAttr = llvm::dyn_cast<StridedLayoutAttr>(attr)) {
2364 stridedLayoutAttr.print(os);
2365 } else if (auto denseArrayAttr = llvm::dyn_cast<DenseArrayAttr>(attr)) {
2367 printType(denseArrayAttr.getElementType());
2368 if (!denseArrayAttr.empty()) {
2370 printDenseArrayAttr(denseArrayAttr);
2374 } else if (auto resourceAttr =
2375 llvm::dyn_cast<DenseResourceElementsAttr>(attr)) {
2376 os << "dense_resource<
";
2377 printResourceHandle(resourceAttr.getRawHandle());
2379 } else if (auto locAttr = llvm::dyn_cast<LocationAttr>(attr)) {
2380 printLocation(locAttr);
2382 llvm::report_fatal_error("Unknown builtin attribute
");
2384 // Don't print the type if we must elide it, or if it is a None type.
2385 if (typeElision != AttrTypeElision::Must) {
2386 if (auto typedAttr = llvm::dyn_cast<TypedAttr>(attr)) {
2387 Type attrType = typedAttr.getType();
2388 if (!llvm::isa<NoneType>(attrType)) {
2390 printType(attrType);
2397 static void printDenseIntElement(const APInt &value, raw_ostream &os,
2399 if (type.isInteger(1))
2400 os << (value.getBoolValue() ? "
true" : "false");
2402 value.print(os, !type.isUnsignedInteger());
2406 printDenseElementsAttrImpl(bool isSplat, ShapedType type, raw_ostream &os,
2407 function_ref<void(unsigned)> printEltFn) {
2408 // Special case for 0-d and splat tensors.
2410 return printEltFn(0);
2412 // Special case for degenerate tensors.
2413 auto numElements = type.getNumElements();
2414 if (numElements == 0)
2417 // We use a mixed-radix counter to iterate through the shape. When we bump a
2418 // non-least-significant digit, we emit a close bracket. When we next emit an
2419 // element we re-open all closed brackets.
2421 // The mixed-radix counter, with radices in 'shape'.
2422 int64_t rank = type.getRank();
2423 SmallVector<unsigned, 4> counter(rank, 0);
2424 // The number of brackets that have been opened and not closed.
2425 unsigned openBrackets = 0;
2427 auto shape = type.getShape();
2428 auto bumpCounter = [&] {
2429 // Bump the least significant digit.
2430 ++counter[rank - 1];
2431 // Iterate backwards bubbling back the increment.
2432 for (unsigned i = rank - 1; i > 0; --i)
2433 if (counter[i] >= shape[i]) {
2434 // Index 'i' is rolled over. Bump (i-1) and close a bracket.
2442 for (unsigned idx = 0, e = numElements; idx != e; ++idx) {
2445 while (openBrackets++ < rank)
2447 openBrackets = rank;
2451 while (openBrackets-- > 0)
2455 void AsmPrinter::Impl::printDenseElementsAttr(DenseElementsAttr attr,
2457 if (auto stringAttr = llvm::dyn_cast<DenseStringElementsAttr>(attr))
2458 return printDenseStringElementsAttr(stringAttr);
2460 printDenseIntOrFPElementsAttr(llvm::cast<DenseIntOrFPElementsAttr>(attr),
2464 void AsmPrinter::Impl::printDenseIntOrFPElementsAttr(
2465 DenseIntOrFPElementsAttr attr, bool allowHex) {
2466 auto type = attr.getType();
2467 auto elementType = type.getElementType();
2469 // Check to see if we should format this attribute as a hex string.
2470 if (allowHex && printerFlags.shouldPrintElementsAttrWithHex(attr)) {
2471 ArrayRef<char> rawData = attr.getRawData();
2472 if (llvm::endianness::native == llvm::endianness::big) {
2473 // Convert endianess in big-endian(BE) machines. `rawData` is BE in BE
2474 // machines. It is converted here to print in LE format.
2475 SmallVector<char, 64> outDataVec(rawData.size());
2476 MutableArrayRef<char> convRawData(outDataVec);
2477 DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
2478 rawData, convRawData, type);
2479 printHexString(convRawData);
2481 printHexString(rawData);
2487 if (ComplexType complexTy = llvm::dyn_cast<ComplexType>(elementType)) {
2488 Type complexElementType = complexTy.getElementType();
2489 // Note: The if and else below had a common lambda function which invoked
2490 // printDenseElementsAttrImpl. This lambda was hitting a bug in gcc 9.1,9.2
2491 // and hence was replaced.
2492 if (llvm::isa<IntegerType>(complexElementType)) {
2493 auto valueIt = attr.value_begin<std::complex<APInt>>();
2494 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2495 auto complexValue = *(valueIt + index);
2497 printDenseIntElement(complexValue.real(), os, complexElementType);
2499 printDenseIntElement(complexValue.imag(), os, complexElementType);
2503 auto valueIt = attr.value_begin<std::complex<APFloat>>();
2504 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2505 auto complexValue = *(valueIt + index);
2507 printFloatValue(complexValue.real(), os);
2509 printFloatValue(complexValue.imag(), os);
2513 } else if (elementType.isIntOrIndex()) {
2514 auto valueIt = attr.value_begin<APInt>();
2515 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2516 printDenseIntElement(*(valueIt + index), os, elementType);
2519 assert(llvm::isa<FloatType>(elementType) && "unexpected element type
");
2520 auto valueIt = attr.value_begin<APFloat>();
2521 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2522 printFloatValue(*(valueIt + index), os);
2527 void AsmPrinter::Impl::printDenseStringElementsAttr(
2528 DenseStringElementsAttr attr) {
2529 ArrayRef<StringRef> data = attr.getRawStringData();
2530 auto printFn = [&](unsigned index) { printEscapedString(data[index]); };
2531 printDenseElementsAttrImpl(attr.isSplat(), attr.getType(), os, printFn);
2534 void AsmPrinter::Impl::printDenseArrayAttr(DenseArrayAttr attr) {
2535 Type type = attr.getElementType();
2536 unsigned bitwidth = type.isInteger(1) ? 8 : type.getIntOrFloatBitWidth();
2537 unsigned byteSize = bitwidth / 8;
2538 ArrayRef<char> data = attr.getRawData();
2540 auto printElementAt = [&](unsigned i) {
2541 APInt value(bitwidth, 0);
2543 llvm::LoadIntFromMemory(
2544 value, reinterpret_cast<const uint8_t *>(data.begin() + byteSize * i),
2547 // Print the data as-is or as a float.
2548 if (type.isIntOrIndex()) {
2549 printDenseIntElement(value, getStream(), type);
2551 APFloat fltVal(llvm::cast<FloatType>(type).getFloatSemantics(), value);
2552 printFloatValue(fltVal, getStream());
2555 llvm::interleaveComma(llvm::seq<unsigned>(0, attr.size()), getStream(),
2559 void AsmPrinter::Impl::printType(Type type) {
2561 os << "<<NULL TYPE>>
";
2565 // Try to print an alias for this type.
2566 if (succeeded(printAlias(type)))
2568 return printTypeImpl(type);
2571 void AsmPrinter::Impl::printTypeImpl(Type type) {
2572 TypeSwitch<Type>(type)
2573 .Case<OpaqueType>([&](OpaqueType opaqueTy) {
2574 printDialectSymbol(os, "!
", opaqueTy.getDialectNamespace(),
2575 opaqueTy.getTypeData());
2577 .Case<IndexType>([&](Type) { os << "index
"; })
2578 .Case<Float6E2M3FNType>([&](Type) { os << "f6E2M3FN
"; })
2579 .Case<Float6E3M2FNType>([&](Type) { os << "f6E3M2FN
"; })
2580 .Case<Float8E5M2Type>([&](Type) { os << "f8E5M2
"; })
2581 .Case<Float8E4M3Type>([&](Type) { os << "f8E4M3
"; })
2582 .Case<Float8E4M3FNType>([&](Type) { os << "f8E4M3FN
"; })
2583 .Case<Float8E5M2FNUZType>([&](Type) { os << "f8E5M2FNUZ
"; })
2584 .Case<Float8E4M3FNUZType>([&](Type) { os << "f8E4M3FNUZ
"; })
2585 .Case<Float8E4M3B11FNUZType>([&](Type) { os << "f8E4M3B11FNUZ
"; })
2586 .Case<Float8E3M4Type>([&](Type) { os << "f8E3M4
"; })
2587 .Case<BFloat16Type>([&](Type) { os << "bf16"; })
2588 .Case<Float16Type>([&](Type) { os << "f16"; })
2589 .Case<FloatTF32Type>([&](Type) { os << "tf32
"; })
2590 .Case<Float32Type>([&](Type) { os << "f32
"; })
2591 .Case<Float64Type>([&](Type) { os << "f64
"; })
2592 .Case<Float80Type>([&](Type) { os << "f80
"; })
2593 .Case<Float128Type>([&](Type) { os << "f128
"; })
2594 .Case<IntegerType>([&](IntegerType integerTy) {
2595 if (integerTy.isSigned())
2597 else if (integerTy.isUnsigned())
2599 os << 'i' << integerTy.getWidth();
2601 .Case<FunctionType>([&](FunctionType funcTy) {
2603 interleaveComma(funcTy.getInputs(), [&](Type ty) { printType(ty); });
2605 ArrayRef<Type> results = funcTy.getResults();
2606 if (results.size() == 1 && !llvm::isa<FunctionType>(results[0])) {
2607 printType(results[0]);
2610 interleaveComma(results, [&](Type ty) { printType(ty); });
2614 .Case<VectorType>([&](VectorType vectorTy) {
2615 auto scalableDims = vectorTy.getScalableDims();
2617 auto vShape = vectorTy.getShape();
2618 unsigned lastDim = vShape.size();
2619 unsigned dimIdx = 0;
2620 for (dimIdx = 0; dimIdx < lastDim; dimIdx++) {
2621 if (!scalableDims.empty() && scalableDims[dimIdx])
2623 os << vShape[dimIdx];
2624 if (!scalableDims.empty() && scalableDims[dimIdx])
2628 printType(vectorTy.getElementType());
2631 .Case<RankedTensorType>([&](RankedTensorType tensorTy) {
2633 printDimensionList(tensorTy.getShape());
2634 if (!tensorTy.getShape().empty())
2636 printType(tensorTy.getElementType());
2637 // Only print the encoding attribute value if set.
2638 if (tensorTy.getEncoding()) {
2640 printAttribute(tensorTy.getEncoding());
2644 .Case<UnrankedTensorType>([&](UnrankedTensorType tensorTy) {
2646 printType(tensorTy.getElementType());
2649 .Case<MemRefType>([&](MemRefType memrefTy) {
2651 printDimensionList(memrefTy.getShape());
2652 if (!memrefTy.getShape().empty())
2654 printType(memrefTy.getElementType());
2655 MemRefLayoutAttrInterface layout = memrefTy.getLayout();
2656 if (!llvm::isa<AffineMapAttr>(layout) || !layout.isIdentity()) {
2658 printAttribute(memrefTy.getLayout(), AttrTypeElision::May);
2660 // Only print the memory space if it is the non-default one.
2661 if (memrefTy.getMemorySpace()) {
2663 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2667 .Case<UnrankedMemRefType>([&](UnrankedMemRefType memrefTy) {
2669 printType(memrefTy.getElementType());
2670 // Only print the memory space if it is the non-default one.
2671 if (memrefTy.getMemorySpace()) {
2673 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2677 .Case<ComplexType>([&](ComplexType complexTy) {
2679 printType(complexTy.getElementType());
2682 .Case<TupleType>([&](TupleType tupleTy) {
2684 interleaveComma(tupleTy.getTypes(),
2685 [&](Type type) { printType(type); });
2688 .Case<NoneType>([&](Type) { os << "none
"; })
2689 .Default([&](Type type) { return printDialectType(type); });
2692 void AsmPrinter::Impl::printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
2693 ArrayRef<StringRef> elidedAttrs,
2695 // If there are no attributes, then there is nothing to be done.
2699 // Functor used to print a filtered attribute list.
2700 auto printFilteredAttributesFn = [&](auto filteredAttrs) {
2701 // Print the 'attributes' keyword if necessary.
2703 os << " attributes
";
2705 // Otherwise, print them all out in braces.
2707 interleaveComma(filteredAttrs,
2708 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2712 // If no attributes are elided, we can directly print with no filtering.
2713 if (elidedAttrs.empty())
2714 return printFilteredAttributesFn(attrs);
2716 // Otherwise, filter out any attributes that shouldn't be included.
2717 llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
2719 auto filteredAttrs = llvm::make_filter_range(attrs, [&](NamedAttribute attr) {
2720 return !elidedAttrsSet.contains(attr.getName().strref());
2722 if (!filteredAttrs.empty())
2723 printFilteredAttributesFn(filteredAttrs);
2725 void AsmPrinter::Impl::printNamedAttribute(NamedAttribute attr) {
2726 // Print the name without quotes if possible.
2727 ::printKeywordOrString(attr.getName().strref(), os);
2729 // Pretty printing elides the attribute value for unit attributes.
2730 if (llvm::isa<UnitAttr>(attr.getValue()))
2734 printAttribute(attr.getValue());
2737 void AsmPrinter::Impl::printDialectAttribute(Attribute attr) {
2738 auto &dialect = attr.getDialect();
2740 // Ask the dialect to serialize the attribute to a string.
2741 std::string attrName;
2743 llvm::raw_string_ostream attrNameStr(attrName);
2744 Impl subPrinter(attrNameStr, state);
2745 DialectAsmPrinter printer(subPrinter);
2746 dialect.printAttribute(attr, printer);
2748 printDialectSymbol(os, "#
", dialect.getNamespace(), attrName);
2751 void AsmPrinter::Impl::printDialectType(Type type) {
2752 auto &dialect = type.getDialect();
2754 // Ask the dialect to serialize the type to a string.
2755 std::string typeName;
2757 llvm::raw_string_ostream typeNameStr(typeName);
2758 Impl subPrinter(typeNameStr, state);
2759 DialectAsmPrinter printer(subPrinter);
2760 dialect.printType(type, printer);
2762 printDialectSymbol(os, "!
", dialect.getNamespace(), typeName);
2765 void AsmPrinter::Impl::printEscapedString(StringRef str) {
2767 llvm::printEscapedString(str, os);
2772 os <<
"\"0x" << llvm::toHex(str) <<
"\"";
2775 printHexString(StringRef(data.data(), data.size()));
2779 return state.pushCyclicPrinting(opaquePointer);
2795 assert(
impl &&
"expected AsmPrinter::getStream to be overriden");
2796 return impl->getStream();
2801 assert(
impl &&
"expected AsmPrinter::printFloat to be overriden");
2806 assert(
impl &&
"expected AsmPrinter::printType to be overriden");
2807 impl->printType(type);
2811 assert(
impl &&
"expected AsmPrinter::printAttribute to be overriden");
2812 impl->printAttribute(attr);
2816 assert(
impl &&
"expected AsmPrinter::printAlias to be overriden");
2817 return impl->printAlias(attr);
2821 assert(
impl &&
"expected AsmPrinter::printAlias to be overriden");
2822 return impl->printAlias(type);
2827 "expected AsmPrinter::printAttributeWithoutType to be overriden");
2832 assert(
impl &&
"expected AsmPrinter::printKeywordOrString to be overriden");
2837 assert(
impl &&
"expected AsmPrinter::printString to be overriden");
2839 printEscapedString(keyword,
getStream());
2844 assert(
impl &&
"expected AsmPrinter::printSymbolName to be overriden");
2849 assert(
impl &&
"expected AsmPrinter::printResourceHandle to be overriden");
2850 impl->printResourceHandle(resource);
2858 return impl->pushCyclicPrinting(opaquePointer);
2869 printAffineExprInternal(expr, BindingStrength::Weak, printValueName);
2875 const char *binopSpelling =
nullptr;
2878 unsigned pos = cast<AffineSymbolExpr>(expr).getPosition();
2880 printValueName(pos,
true);
2886 unsigned pos = cast<AffineDimExpr>(expr).getPosition();
2888 printValueName(pos,
false);
2894 os << cast<AffineConstantExpr>(expr).getValue();
2897 binopSpelling =
" + ";
2900 binopSpelling =
" * ";
2903 binopSpelling =
" floordiv ";
2906 binopSpelling =
" ceildiv ";
2909 binopSpelling =
" mod ";
2913 auto binOp = cast<AffineBinaryOpExpr>(expr);
2919 if (enclosingTightness == BindingStrength::Strong)
2923 auto rhsConst = dyn_cast<AffineConstantExpr>(rhsExpr);
2925 rhsConst.getValue() == -1) {
2927 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
2928 if (enclosingTightness == BindingStrength::Strong)
2933 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
2935 os << binopSpelling;
2936 printAffineExprInternal(rhsExpr, BindingStrength::Strong, printValueName);
2938 if (enclosingTightness == BindingStrength::Strong)
2944 if (enclosingTightness == BindingStrength::Strong)
2949 if (
auto rhs = dyn_cast<AffineBinaryOpExpr>(rhsExpr)) {
2952 if (
auto rrhs = dyn_cast<AffineConstantExpr>(rrhsExpr)) {
2953 if (rrhs.getValue() == -1) {
2954 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
2958 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
2961 printAffineExprInternal(rhs.getLHS(), BindingStrength::Weak,
2965 if (enclosingTightness == BindingStrength::Strong)
2970 if (rrhs.getValue() < -1) {
2971 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
2974 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
2976 os <<
" * " << -rrhs.getValue();
2977 if (enclosingTightness == BindingStrength::Strong)
2986 if (
auto rhsConst = dyn_cast<AffineConstantExpr>(rhsExpr)) {
2987 if (rhsConst.getValue() < 0) {
2988 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
2989 os <<
" - " << -rhsConst.getValue();
2990 if (enclosingTightness == BindingStrength::Strong)
2996 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
2999 printAffineExprInternal(rhsExpr, BindingStrength::Weak, printValueName);
3001 if (enclosingTightness == BindingStrength::Strong)
3006 printAffineExprInternal(expr, BindingStrength::Weak);
3007 isEq ? os <<
" == 0" : os <<
" >= 0";
3013 for (
int i = 0; i < (int)map.
getNumDims() - 1; ++i)
3014 os <<
'd' << i <<
", ";
3023 os <<
's' << i <<
", ";
3032 [&](
AffineExpr expr) { printAffineExpr(expr); });
3039 for (
unsigned i = 1; i < set.
getNumDims(); ++i)
3040 os <<
'd' << i - 1 <<
", ";
3049 os <<
's' << i <<
", ";
3058 for (
int i = 1; i < numConstraints; ++i) {
3062 if (numConstraints >= 1)
3063 printAffineConstraint(set.
getConstraint(numConstraints - 1),
3064 set.
isEq(numConstraints - 1));
3079 explicit OperationPrinter(raw_ostream &os,
AsmStateImpl &state)
3083 void printTopLevelOperation(
Operation *op);
3087 void printFullOpWithIndentAndLoc(
Operation *op);
3093 void printCustomOrGenericOp(
Operation *op)
override;
3095 void printGenericOp(
Operation *op,
bool printOpName)
override;
3098 void printBlockName(
Block *block);
3103 void print(
Block *block,
bool printBlockArgs =
true,
3104 bool printBlockTerminator =
true);
3107 void printValueID(
Value value,
bool printResultNo =
true,
3108 raw_ostream *streamOverride =
nullptr)
const;
3112 raw_ostream *streamOverride =
nullptr)
const;
3120 void printOptionalLocationSpecifier(
Location loc)
override {
3121 printTrailingLocation(loc);
3128 os.indent(currentIndent);
3132 void increaseIndent()
override { currentIndent += indentWidth; }
3135 void decreaseIndent()
override { currentIndent -= indentWidth; }
3144 bool omitType =
false)
override;
3147 void printOperand(
Value value)
override { printValueID(value); }
3148 void printOperand(
Value value, raw_ostream &os)
override {
3149 printValueID(value,
true, &os);
3157 void printOptionalAttrDictWithKeyword(
3165 void printSuccessor(
Block *successor)
override;
3169 void printSuccessorAndUseList(
Block *successor,
3174 bool printBlockTerminators,
bool printEmptyBlock)
override;
3181 state.getSSANameState().shadowRegionArgs(region, namesToUse);
3186 void printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3201 void printValueUsers(
Value value);
3205 void printUserIDs(
Operation *user,
bool prefixComma =
false);
3213 using PrintFn =
function_ref<void(StringRef, ValueFn)>;
3215 ResourceBuilder(PrintFn printFn) : printFn(printFn) {}
3216 ~ResourceBuilder()
override =
default;
3218 void buildBool(StringRef key,
bool data)
final {
3219 printFn(key, [&](raw_ostream &os) { os << (data ?
"true" :
"false"); });
3222 void buildString(StringRef key, StringRef data)
final {
3223 printFn(key, [&](raw_ostream &os) {
3225 llvm::printEscapedString(data, os);
3231 uint32_t dataAlignment)
final {
3232 printFn(key, [&](raw_ostream &os) {
3234 llvm::support::ulittle32_t dataAlignmentLE(dataAlignment);
3236 << llvm::toHex(StringRef(
reinterpret_cast<char *
>(&dataAlignmentLE),
3237 sizeof(dataAlignment)))
3238 << llvm::toHex(StringRef(data.data(), data.size())) <<
"\"";
3247 void printFileMetadataDictionary(
Operation *op);
3253 void printResourceFileMetadata(
function_ref<
void()> checkAddMetadataDict,
3264 const static unsigned indentWidth = 2;
3267 unsigned currentIndent = 0;
3271 void OperationPrinter::printTopLevelOperation(
Operation *op) {
3273 state.getAliasState().printNonDeferredAliases(*
this, newLine);
3276 printFullOpWithIndentAndLoc(op);
3280 state.getAliasState().printDeferredAliases(*
this, newLine);
3283 printFileMetadataDictionary(op);
3286 void OperationPrinter::printFileMetadataDictionary(
Operation *op) {
3287 bool sawMetadataEntry =
false;
3288 auto checkAddMetadataDict = [&] {
3289 if (!std::exchange(sawMetadataEntry,
true))
3290 os << newLine <<
"{-#" << newLine;
3294 printResourceFileMetadata(checkAddMetadataDict, op);
3297 if (sawMetadataEntry)
3298 os << newLine <<
"#-}" << newLine;
3301 void OperationPrinter::printResourceFileMetadata(
3304 bool hadResource =
false;
3305 bool needResourceComma =
false;
3306 bool needEntryComma =
false;
3307 auto processProvider = [&](StringRef dictName, StringRef name,
auto &provider,
3308 auto &&...providerArgs) {
3309 bool hadEntry =
false;
3310 auto printFn = [&](StringRef key, ResourceBuilder::ValueFn valueFn) {
3311 checkAddMetadataDict();
3313 auto printFormatting = [&]() {
3315 if (!std::exchange(hadResource,
true)) {
3316 if (needResourceComma)
3317 os <<
"," << newLine;
3318 os <<
" " << dictName <<
"_resources: {" << newLine;
3321 if (!std::exchange(hadEntry,
true)) {
3323 os <<
"," << newLine;
3324 os <<
" " << name <<
": {" << newLine;
3326 os <<
"," << newLine;
3330 std::optional<uint64_t> charLimit =
3332 if (charLimit.has_value()) {
3333 std::string resourceStr;
3334 llvm::raw_string_ostream ss(resourceStr);
3338 if (resourceStr.size() > charLimit.value())
3342 os <<
" " << key <<
": " << resourceStr;
3345 os <<
" " << key <<
": ";
3349 ResourceBuilder entryBuilder(printFn);
3350 provider.buildResources(op, providerArgs..., entryBuilder);
3352 needEntryComma |= hadEntry;
3354 os << newLine <<
" }";
3360 auto &dialectResources = state.getDialectResources();
3361 StringRef name = interface.getDialect()->getNamespace();
3362 auto it = dialectResources.find(interface.getDialect());
3363 if (it != dialectResources.end())
3364 processProvider(
"dialect", name, interface, it->second);
3366 processProvider(
"dialect", name, interface,
3370 os << newLine <<
" }";
3374 needEntryComma =
false;
3375 needResourceComma = hadResource;
3376 hadResource =
false;
3377 for (
const auto &printer : state.getResourcePrinters())
3378 processProvider(
"external", printer.getName(), printer);
3380 os << newLine <<
" }";
3388 void OperationPrinter::printRegionArgument(
BlockArgument arg,
3396 printOptionalAttrDict(argAttrs);
3398 printTrailingLocation(arg.
getLoc(),
false);
3401 void OperationPrinter::printFullOpWithIndentAndLoc(
Operation *op) {
3403 state.registerOperationLocation(op, newLine.curLine, currentIndent);
3405 os.indent(currentIndent);
3407 printTrailingLocation(op->
getLoc());
3409 printUsersComment(op);
3412 void OperationPrinter::printFullOp(
Operation *op) {
3414 auto printResultGroup = [&](
size_t resultNo,
size_t resultCount) {
3415 printValueID(op->
getResult(resultNo),
false);
3416 if (resultCount > 1)
3417 os <<
':' << resultCount;
3421 ArrayRef<int> resultGroups = state.getSSANameState().getOpResultGroups(op);
3422 if (!resultGroups.empty()) {
3425 interleaveComma(llvm::seq<int>(0, resultGroups.size() - 1), [&](
int i) {
3426 printResultGroup(resultGroups[i],
3427 resultGroups[i + 1] - resultGroups[i]);
3430 printResultGroup(resultGroups.back(), numResults - resultGroups.back());
3433 printResultGroup(0, numResults);
3439 printCustomOrGenericOp(op);
3442 void OperationPrinter::printUsersComment(
Operation *op) {
3446 printOperationID(op);
3447 }
else if (numResults && op->
use_empty()) {
3449 }
else if (numResults && !op->
use_empty()) {
3452 unsigned usedInNResults = 0;
3453 unsigned usedInNOperations = 0;
3456 if (userSet.insert(user).second) {
3457 ++usedInNOperations;
3458 usedInNResults += user->getNumResults();
3463 bool exactlyOneUniqueUse =
3464 usedInNResults <= 1 && usedInNOperations <= 1 && numResults == 1;
3465 os <<
" // " << (exactlyOneUniqueUse ?
"user" :
"users") <<
": ";
3466 bool shouldPrintBrackets = numResults > 1;
3467 auto printOpResult = [&](
OpResult opResult) {
3468 if (shouldPrintBrackets)
3470 printValueUsers(opResult);
3471 if (shouldPrintBrackets)
3475 interleaveComma(op->
getResults(), printOpResult);
3479 void OperationPrinter::printUsersComment(
BlockArgument arg) {
3485 os <<
" is used by ";
3486 printValueUsers(arg);
3491 void OperationPrinter::printValueUsers(
Value value) {
3499 if (userSet.insert(user).second)
3500 printUserIDs(user, index);
3504 void OperationPrinter::printUserIDs(
Operation *user,
bool prefixComma) {
3509 printOperationID(user);
3512 [
this](
Value result) { printValueID(result); });
3516 void OperationPrinter::printCustomOrGenericOp(
Operation *op) {
3522 opInfo->printAssembly(op, *
this, defaultDialectStack.back());
3527 if (
auto opPrinter = dialect->getOperationPrinter(op)) {
3532 if (name.count(
'.') == 1)
3533 name.consume_front((defaultDialectStack.back() +
".").str());
3537 opPrinter(op, *
this);
3544 printGenericOp(op,
true);
3547 void OperationPrinter::printGenericOp(
Operation *op,
bool printOpName) {
3551 interleaveComma(op->
getOperands(), [&](
Value value) { printValueID(value); });
3558 [&](
Block *successor) { printBlockName(successor); });
3570 if (op->getNumRegions() != 0) {
3572 interleaveComma(op->getRegions(), [&](Region ®ion) {
3573 printRegion(region, /*printEntryBlockArgs=*/true,
3574 /*printBlockTerminators=*/true, /*printEmptyBlock=*/true);
3579 printOptionalAttrDict(op->getPropertiesStorage()
3580 ? llvm::to_vector(op->getDiscardableAttrs())
3583 // Print the type signature of the operation.
3585 printFunctionalType(op);
3588 void OperationPrinter::printBlockName(Block *block) {
3589 os << state.getSSANameState().getBlockInfo(block).name;
3592 void OperationPrinter::print(Block *block, bool printBlockArgs,
3593 bool printBlockTerminator) {
3594 // Print the block label and argument list if requested.
3595 if (printBlockArgs) {
3596 os.indent(currentIndent);
3597 printBlockName(block);
3599 // Print the argument list if non-empty.
3600 if (!block->args_empty()) {
3602 interleaveComma(block->getArguments(), [&](BlockArgument arg) {
3605 printType(arg.getType());
3606 // TODO: We should allow location aliases on block arguments.
3607 printTrailingLocation(arg.getLoc(), /*allowAlias*/ false);
3613 // Print out some context information about the predecessors of this block.
3614 if (!block->getParent()) {
3615 os << " // block is not in a region!";
3616 } else if (block->hasNoPredecessors()) {
3617 if (!block->isEntryBlock())
3618 os << " // no predecessors";
3619 } else if (auto *pred = block->getSinglePredecessor()) {
3621 printBlockName(pred);
3623 // We want to print the predecessors in a stable order, not in
3624 // whatever order the use-list is in, so gather and sort them.
3625 SmallVector<BlockInfo, 4> predIDs;
3626 for (auto *pred : block->getPredecessors())
3627 predIDs.push_back(state.getSSANameState().getBlockInfo(pred));
3628 llvm::sort(predIDs, [](BlockInfo lhs, BlockInfo rhs) {
3629 return lhs.ordering < rhs.ordering;
3632 os << " // " << predIDs.size() << " preds: ";
3634 interleaveComma(predIDs, [&](BlockInfo pred) { os << pred.name; });
3639 currentIndent += indentWidth;
3641 if (printerFlags.shouldPrintValueUsers()) {
3642 for (BlockArgument arg : block->getArguments()) {
3643 os.indent(currentIndent);
3644 printUsersComment(arg);
3648 bool hasTerminator =
3649 !block->empty() && block->back().hasTrait<OpTrait::IsTerminator>();
3650 auto range = llvm::make_range(
3652 std::prev(block->end(),
3653 (!hasTerminator || printBlockTerminator) ? 0 : 1));
3654 for (auto &op : range) {
3655 printFullOpWithIndentAndLoc(&op);
3658 currentIndent -= indentWidth;
3661 void OperationPrinter::printValueID(Value value, bool printResultNo,
3662 raw_ostream *streamOverride) const {
3663 state.getSSANameState().printValueID(value, printResultNo,
3664 streamOverride ? *streamOverride : os);
3667 void OperationPrinter::printOperationID(Operation *op,
3668 raw_ostream *streamOverride) const {
3669 state.getSSANameState().printOperationID(op, streamOverride ? *streamOverride
3673 void OperationPrinter::printSuccessor(Block *successor) {
3674 printBlockName(successor);
3677 void OperationPrinter::printSuccessorAndUseList(Block *successor,
3678 ValueRange succOperands) {
3679 printBlockName(successor);
3680 if (succOperands.empty())
3684 interleaveComma(succOperands,
3685 [this](Value operand) { printValueID(operand); });
3687 interleaveComma(succOperands,
3688 [this](Value operand) { printType(operand.getType()); });
3692 void OperationPrinter::printRegion(Region ®ion, bool printEntryBlockArgs,
3693 bool printBlockTerminators,
3694 bool printEmptyBlock) {
3695 if (printerFlags.shouldSkipRegions()) {
3699 os << "{" << newLine;
3700 if (!region.empty()) {
3701 auto restoreDefaultDialect =
3702 llvm::make_scope_exit([&]() { defaultDialectStack.pop_back(); });
3703 if (auto iface = dyn_cast<OpAsmOpInterface>(region.getParentOp()))
3704 defaultDialectStack.push_back(iface.getDefaultDialect());
3706 defaultDialectStack.push_back("");
3708 auto *entryBlock = ®ion.front();
3709 // Force printing the block header if printEmptyBlock is set and the block
3710 // is empty or if printEntryBlockArgs is set and there are arguments to
3712 bool shouldAlwaysPrintBlockHeader =
3713 (printEmptyBlock && entryBlock->empty()) ||
3714 (printEntryBlockArgs && entryBlock->getNumArguments() != 0);
3715 print(entryBlock, shouldAlwaysPrintBlockHeader, printBlockTerminators);
3716 for (auto &b : llvm::drop_begin(region.getBlocks(), 1))
3719 os.indent(currentIndent) << "}";
3722 void OperationPrinter::printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3723 ValueRange operands) {
3725 os << "<<NULL AFFINE MAP>>";
3728 AffineMap map = mapAttr.getValue();
3729 unsigned numDims = map.getNumDims();
3730 auto printValueName = [&](unsigned pos, bool isSymbol) {
3731 unsigned index = isSymbol ? numDims + pos : pos;
3732 assert(index < operands.size());
3735 printValueID(operands[index]);
3740 interleaveComma(map.getResults(), [&](AffineExpr expr) {
3741 printAffineExpr(expr, printValueName);
3745 void OperationPrinter::printAffineExprOfSSAIds(AffineExpr expr,
3746 ValueRange dimOperands,
3747 ValueRange symOperands) {
3748 auto printValueName = [&](unsigned pos, bool isSymbol) {
3750 return printValueID(dimOperands[pos]);
3752 printValueID(symOperands[pos]);
3755 printAffineExpr(expr, printValueName);
3758 //===----------------------------------------------------------------------===//
3759 // print and dump methods
3760 //===----------------------------------------------------------------------===//
3762 void Attribute::print(raw_ostream &os, bool elideType) const {
3764 os << "<<NULL ATTRIBUTE>>";
3768 AsmState state(getContext());
3769 print(os, state, elideType);
3771 void Attribute::print(raw_ostream &os, AsmState &state, bool elideType) const {
3772 using AttrTypeElision = AsmPrinter::Impl::AttrTypeElision;
3773 AsmPrinter::Impl(os, state.getImpl())
3774 .printAttribute(*this, elideType ? AttrTypeElision::Must
3775 : AttrTypeElision::Never);
3778 void Attribute::dump() const {
3779 print(llvm::errs());
3780 llvm::errs() << "\n";
3783 void Attribute::printStripped(raw_ostream &os, AsmState &state) const {
3785 os << "<<NULL ATTRIBUTE>>";
3789 AsmPrinter::Impl subPrinter(os, state.getImpl());
3790 if (succeeded(subPrinter.printAlias(*this)))
3793 auto &dialect = this->getDialect();
3794 uint64_t posPrior = os.tell();
3795 DialectAsmPrinter printer(subPrinter);
3796 dialect.printAttribute(*this, printer);
3797 if (posPrior != os.tell())
3800 // Fallback to printing with prefix if the above failed to write anything
3801 // to the output stream.
3804 void Attribute::printStripped(raw_ostream &os) const {
3806 os << "<<NULL ATTRIBUTE>>";
3810 AsmState state(getContext());
3811 printStripped(os, state);
3814 void Type::print(raw_ostream &os) const {
3816 os << "<<NULL TYPE>>";
3820 AsmState state(getContext());
3823 void Type::print(raw_ostream &os, AsmState &state) const {
3824 AsmPrinter::Impl(os, state.getImpl()).printType(*this);
3827 void Type::dump() const {
3828 print(llvm::errs());
3829 llvm::errs() << "\n";
3832 void AffineMap::dump() const {
3833 print(llvm::errs());
3834 llvm::errs() << "\n";
3837 void IntegerSet::dump() const {
3838 print(llvm::errs());
3839 llvm::errs() << "\n";
3842 void AffineExpr::print(raw_ostream &os) const {
3844 os << "<<NULL AFFINE EXPR>>";
3847 AsmState state(getContext());
3848 AsmPrinter::Impl(os, state.getImpl()).printAffineExpr(*this);
3851 void AffineExpr::dump() const {
3852 print(llvm::errs());
3853 llvm::errs() << "\n";
3856 void AffineMap::print(raw_ostream &os) const {
3858 os << "<<NULL AFFINE MAP>>";
3861 AsmState state(getContext());
3862 AsmPrinter::Impl(os, state.getImpl()).printAffineMap(*this);
3865 void IntegerSet::print(raw_ostream &os) const {
3866 AsmState state(getContext());
3867 AsmPrinter::Impl(os, state.getImpl()).printIntegerSet(*this);
3870 void Value::print(raw_ostream &os) const { print(os, OpPrintingFlags()); }
3871 void Value::print(raw_ostream &os, const OpPrintingFlags &flags) const {
3873 os << "<<NULL VALUE>>";
3877 if (auto *op = getDefiningOp())
3878 return op->print(os, flags);
3879 // TODO: Improve BlockArgument print'ing.
3881 os <<
"<block argument> of type '" << arg.
getType()
3886 os <<
"<<NULL VALUE>>";
3890 if (
auto *op = getDefiningOp())
3891 return op->
print(os, state);
3895 os <<
"<block argument> of type '" << arg.
getType()
3900 print(llvm::errs());
3901 llvm::errs() <<
"\n";
3909 state.getImpl().getSSANameState().printValueID(*
this,
true,
3932 if (
auto result = llvm::dyn_cast<OpResult>(*
this)) {
3935 op = llvm::cast<BlockArgument>(*this).getOwner()->
getParentOp();
3937 os <<
"<<UNKNOWN SSA VALUE>>";
3943 printAsOperand(os, state);
3953 OperationPrinter printer(os, state.getImpl());
3954 if (!getParent() && !state.getPrinterFlags().shouldUseLocalScope()) {
3955 state.getImpl().initializeAliases(
this);
3956 printer.printTopLevelOperation(
this);
3958 printer.printFullOpWithIndentAndLoc(
this);
3964 llvm::errs() <<
"\n";
3970 os <<
"<<UNLINKED BLOCK>>\n";
3981 OperationPrinter(os, state.getImpl()).print(
this);
3990 os <<
"<<UNLINKED BLOCK>>\n";
3994 printAsOperand(os, state);
3997 OperationPrinter printer(os, state.getImpl());
3998 printer.printBlockName(
this);
4013 if (dimensions.empty())
4016 if (dimensions.empty())
4026 <<
"Failed parsing dimension list.";
4037 <<
"Failed parsing dimension list.";
4039 if (shapeArr.empty()) {
4041 <<
"Failed parsing dimension list. Did you mean an empty list? It "
4042 "must be denoted by \"[]\".";
static StringRef sanitizeIdentifier(StringRef name, SmallString< 16 > &buffer, StringRef allowedPunctChars="$._-", bool allowTrailingDigit=true)
Sanitize the given name such that it can be used as a valid identifier.
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 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)
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.
Dialect * getDialect() const
Return the dialect that owns the resource.
This class represents a single parsed resource entry.
virtual FailureOr< AsmResourceBlob > parseAsBlob(BlobAllocatorFn allocator) const =0
Parse the resource entry represented by a binary blob.
virtual InFlightDiagnostic emitError() const =0
Emit an error at the location of this entry.
virtual AsmResourceEntryKind getKind() const =0
Return the kind of this value.
virtual FailureOr< std::string > parseAsString() const =0
Parse the resource entry represented by a human-readable string.
virtual FailureOr< bool > parseAsBool() const =0
Parse the resource entry represented by a boolean.
virtual StringRef getKey() const =0
Return the key of the resource entry.
MLIRContext * getContext() const
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
virtual ParseResult parseRSquare()=0
Parse a ] token.
virtual ParseResult parseDimensionList(SmallVectorImpl< int64_t > &dimensions, bool allowDynamic=true, bool withTrailingX=true)=0
Parse a dimension list of a tensor or memref type.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
ParseResult parseTypeList(SmallVectorImpl< Type > &result)
Parse a type list.
virtual ParseResult parseOptionalLSquare()=0
Parse a [ token if present.
Impl(raw_ostream &os, AsmStateImpl &state)
BindingStrength
This enum is used to represent the binding strength of the enclosing context that an AffineExprStorag...
void printHexString(StringRef str)
Print a hex string, wrapped with "".
void printDenseArrayAttr(DenseArrayAttr attr)
Print a dense array attribute.
void printDenseElementsAttr(DenseElementsAttr attr, bool allowHex)
Print a dense elements attribute.
void printAttribute(Attribute attr, AttrTypeElision typeElision=AttrTypeElision::Never)
Print the given attribute or an alias.
void printDimensionList(ArrayRef< int64_t > shape)
OpPrintingFlags printerFlags
A set of flags to control the printer's behavior.
raw_ostream & os
The output stream for the printer.
void printResourceHandle(const AsmDialectResourceHandle &resource)
Print a reference to the given resource that is owned by the given dialect.
raw_ostream & getStream()
Returns the output stream of the printer.
LogicalResult printAlias(Attribute attr)
Print the alias for the given attribute, return failure if no alias could be printed.
void printDialectAttribute(Attribute attr)
void interleaveComma(const Container &c, UnaryFunctor eachFn) const
void printDialectType(Type type)
void printLocation(LocationAttr loc, bool allowAlias=false)
Print the given location to the stream.
AsmStateImpl & state
An underlying assembly printer state.
void printAffineMap(AffineMap map)
void printTrailingLocation(Location loc, bool allowAlias=true)
void printAffineExprInternal(AffineExpr expr, BindingStrength enclosingTightness, function_ref< void(unsigned, bool)> printValueName=nullptr)
void printEscapedString(StringRef str)
Print an escaped string, wrapped with "".
void printAffineExpr(AffineExpr expr, function_ref< void(unsigned, bool)> printValueName=nullptr)
void printDenseStringElementsAttr(DenseStringElementsAttr attr)
Print a dense string elements attribute.
void printAttributeImpl(Attribute attr, AttrTypeElision typeElision=AttrTypeElision::Never)
Print the given attribute without considering an alias.
void printAffineConstraint(AffineExpr expr, bool isEq)
void printDenseIntOrFPElementsAttr(DenseIntOrFPElementsAttr attr, bool allowHex)
Print a dense elements attribute.
AttrTypeElision
This enum describes the different kinds of elision for the type of an attribute when printing it.
@ May
The type may be elided when it matches the default used in the parser (for example i64 is the default...
@ Never
The type must not be elided,.
@ Must
The type must be elided.
LogicalResult pushCyclicPrinting(const void *opaquePointer)
void printIntegerSet(IntegerSet set)
NewLineCounter newLine
A tracker for the number of new lines emitted during printing.
void printOptionalAttrDict(ArrayRef< NamedAttribute > attrs, ArrayRef< StringRef > elidedAttrs={}, bool withKeyword=false)
void printType(Type type)
Print the given type or an alias.
void printLocationInternal(LocationAttr loc, bool pretty=false, bool isTopLevel=false)
void printTypeImpl(Type type)
Print the given type.
void printNamedAttribute(NamedAttribute attr)
virtual void printAttributeWithoutType(Attribute attr)
Print the given attribute without its type.
virtual LogicalResult printAlias(Attribute attr)
Print the alias for the given attribute, return failure if no alias could be printed.
virtual void popCyclicPrinting()
Removes the element that was last inserted with a successful call to pushCyclicPrinting.
virtual LogicalResult pushCyclicPrinting(const void *opaquePointer)
Pushes a new attribute or type in the form of a type erased pointer into an internal set.
virtual void printType(Type type)
virtual void printKeywordOrString(StringRef keyword)
Print the given string as a keyword, or a quoted and escaped string if it has any special or non-prin...
virtual void printSymbolName(StringRef symbolRef)
Print the given string as a symbol reference, i.e.
virtual void printString(StringRef string)
Print the given string as a quoted string, escaping any special or non-printable characters in it.
virtual void printAttribute(Attribute attr)
void printDimensionList(ArrayRef< int64_t > shape)
virtual raw_ostream & getStream() const
Return the raw output stream used by this printer.
virtual void printResourceHandle(const AsmDialectResourceHandle &resource)
Print a handle to the given dialect resource.
virtual void printFloat(const APFloat &value)
Print the given floating point value in a stabilized form that can be roundtripped through the IR.
This class is used to build resource entries for use by the printer.
virtual void buildString(StringRef key, StringRef data)=0
Build a resource entry represented by the given human-readable string value.
virtual void buildBool(StringRef key, bool data)=0
Build a resource entry represented by the given bool.
virtual void buildBlob(StringRef key, ArrayRef< char > data, uint32_t dataAlignment)=0
Build an resource entry represented by the given binary blob data.
This class represents an instance of a resource parser.
static std::unique_ptr< AsmResourcePrinter > fromCallable(StringRef name, CallableT &&printFn)
Return a resource printer implemented via the given callable, whose form should match that of buildRe...
This class provides management for the lifetime of the state used when printing the IR.
void attachResourcePrinter(std::unique_ptr< AsmResourcePrinter > printer)
Attach the given resource printer to the AsmState.
DenseMap< Dialect *, SetVector< AsmDialectResourceHandle > > & getDialectResources() const
Returns a map of dialect resources that were referenced when using this state to print IR.
void attachFallbackResourcePrinter(FallbackAsmResourceMap &map)
Attach resource printers to the AsmState for the fallback resources in the given map.
const OpPrintingFlags & getPrinterFlags() const
Get the printer flags.
Attributes are known-constant values of operations.
Dialect & getDialect() const
Get the dialect this attribute is registered to.
bool hasTrait()
Returns true if the type was registered with a particular trait.
const void * getAsOpaquePointer() const
Get an opaque pointer to the attribute.
static Attribute getFromOpaquePointer(const void *ptr)
Construct an attribute from the opaque pointer representation.
This class represents an argument of a Block.
Location getLoc() const
Return the location for this argument.
unsigned getArgNumber() const
Returns the number of this argument.
Block represents an ordered list of Operations.
void printAsOperand(raw_ostream &os, bool printType=true)
Print out the name of the block without printing its body.
void print(raw_ostream &os)
BlockArgListType getArguments()
bool isEntryBlock()
Return if this block is the entry block in the parent region.
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
An attribute that represents a reference to a dense vector or tensor object.
This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine.
~DialectAsmParser() override
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
~DialectAsmPrinter() override
A collection of dialect interfaces within a context, for a given concrete interface type.
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
virtual void printAttribute(Attribute, DialectAsmPrinter &) const
Print an attribute registered to this dialect.
virtual void printType(Type, DialectAsmPrinter &) const
Print a type registered to this dialect.
An attribute that associates a referenced attribute with a unique identifier.
A fallback map containing external resources not explicitly handled by another parser/printer.
std::vector< std::unique_ptr< AsmResourcePrinter > > getPrinters()
Build a set of resource printers to print the resources within this map.
An integer set representing a conjunction of one or more affine equalities and inequalities.
unsigned getNumDims() const
unsigned getNumConstraints() const
AffineExpr getConstraint(unsigned idx) const
bool isEq(unsigned idx) const
Returns true if the idx^th constraint is an equality, false if it is an inequality.
unsigned getNumSymbols() const
Location objects represent source locations information in MLIR.
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 std::string getResourceKey(const AsmDialectResourceHandle &handle) const
Return a key to use for the given resource.
virtual LogicalResult parseResource(AsmParsedResourceEntry &entry) const
Hook for parsing resource entries.
AliasResult
Holds the result of getAlias hook call.
@ FinalAlias
An alias was provided and it should be used (no other hooks will be checked).
@ NoAlias
The object (type or attribute) is not supported by the hook and an alias was not provided.
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 shouldAssumeVerified() const
Return if operation verification should be skipped.
OpPrintingFlags & printValueUsers()
Print users of values as comments.
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 & 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 & assumeVerified()
Do not verify the operation when using custom operation printers.
std::optional< uint64_t > getLargeResourceStringLimit() const
Return the size limit in chars for printing large resources.
OpPrintingFlags & useLocalScope()
Use local scope when printing the operation.
OpPrintingFlags & skipRegions(bool skip=true)
Skip printing regions.
This is a value defined by a result of an operation.
Operation * getOwner() const
Returns the operation that owns this result.
unsigned getResultNumber() const
Returns the number of this result.
This class provides the API for ops that are known to be isolated from above.
This class provides the API for ops that are known to be terminators.
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
void printAssembly(Operation *op, OpAsmPrinter &p, StringRef defaultDialect) const
This hook implements the AsmPrinter for this operation.
void print(raw_ostream &os) const
Operation is the basic unit of execution within MLIR.
bool use_empty()
Returns true if this operation has no uses.
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
Dialect * getDialect()
Return the dialect this operation is associated with, or nullptr if the associated dialect is not loa...
unsigned getNumSuccessors()
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
void print(raw_ostream &os, const OpPrintingFlags &flags=std::nullopt)
MLIRContext * getContext()
Return the context this operation is associated with.
std::optional< RegisteredOperationName > getRegisteredInfo()
If this operation has a registered operation description, return it.
Location getLoc()
The source location the operation was defined or derived from.
unsigned getNumOperands()
Attribute getPropertiesAsAttribute()
Return the properties converted to an attribute.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
ArrayRef< NamedAttribute > getAttrs()
Return all of the attributes on this operation.
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
OperationName getName()
The name of an operation is the key identifier for it.
operand_type_range getOperandTypes()
result_type_range getResultTypes()
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()
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)
bool hasTrait()
Returns true if the type was registered with a particular trait.
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
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)
@ 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.