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;
551 bool isPrinted =
false;
557 class AliasInitializer {
561 llvm::BumpPtrAllocator &aliasAllocator)
562 : interfaces(interfaces), aliasAllocator(aliasAllocator),
563 aliasOS(aliasBuffer) {}
566 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias);
574 std::pair<size_t, size_t>
visit(
Attribute attr,
bool canBeDeferred =
false,
575 bool elideType =
false) {
576 return visitImpl(attr, aliases, canBeDeferred, elideType);
583 std::pair<size_t, size_t>
visit(
Type type,
bool canBeDeferred =
false) {
584 return visitImpl(type, aliases, canBeDeferred);
588 struct InProgressAliasInfo {
589 InProgressAliasInfo()
590 : aliasDepth(0), isType(false), canBeDeferred(false) {}
591 InProgressAliasInfo(StringRef alias)
592 : alias(alias), aliasDepth(1), isType(false), canBeDeferred(false) {}
594 bool operator<(
const InProgressAliasInfo &rhs)
const {
596 if (aliasDepth != rhs.aliasDepth)
597 return aliasDepth < rhs.aliasDepth;
598 if (isType != rhs.isType)
600 return alias < rhs.alias;
605 std::optional<StringRef> alias;
608 unsigned aliasDepth : 30;
612 bool canBeDeferred : 1;
622 template <
typename T,
typename... PrintArgs>
623 std::pair<size_t, size_t>
625 llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
626 bool canBeDeferred, PrintArgs &&...printArgs);
629 void markAliasNonDeferrable(
size_t aliasIndex);
633 template <
typename T>
634 void generateAlias(T symbol, InProgressAliasInfo &alias,
bool canBeDeferred);
638 static void initializeAliases(
639 llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
640 llvm::MapVector<const void *, SymbolAlias> &symbolToAlias);
646 llvm::BumpPtrAllocator &aliasAllocator;
649 llvm::MapVector<const void *, InProgressAliasInfo> aliases;
653 llvm::raw_svector_ostream aliasOS;
661 class DummyAliasOperationPrinter :
private OpAsmPrinter {
663 explicit DummyAliasOperationPrinter(
const OpPrintingFlags &printerFlags,
664 AliasInitializer &initializer)
665 : printerFlags(printerFlags), initializer(initializer) {}
669 void printCustomOrGenericOp(
Operation *op)
override {
671 if (printerFlags.shouldPrintDebugInfo())
672 initializer.visit(op->
getLoc(),
true);
675 if (!printerFlags.shouldPrintGenericOpForm()) {
686 void printGenericOp(
Operation *op,
bool printOpName =
true)
override {
688 if (!printerFlags.shouldSkipRegions()) {
702 printAttribute(attr.getValue());
708 void print(
Block *block,
bool printBlockArgs =
true,
709 bool printBlockTerminator =
true) {
712 if (printBlockArgs) {
717 if (printerFlags.shouldPrintDebugInfo())
719 initializer.visit(arg.getLoc(),
false);
727 auto range = llvm::make_range(
729 std::prev(block->
end(),
730 (!hasTerminator || printBlockTerminator) ? 0 : 1));
732 printCustomOrGenericOp(&op);
737 bool printBlockTerminators,
738 bool printEmptyBlock =
false)
override {
741 if (printerFlags.shouldSkipRegions()) {
746 auto *entryBlock = ®ion.
front();
747 print(entryBlock, printEntryBlockArgs, printBlockTerminators);
748 for (
Block &b : llvm::drop_begin(region, 1))
753 bool omitType)
override {
756 if (printerFlags.shouldPrintDebugInfo())
758 initializer.visit(arg.
getLoc(),
false);
762 void printType(
Type type)
override { initializer.visit(type); }
765 void printAttribute(
Attribute attr)
override { initializer.visit(attr); }
766 void printAttributeWithoutType(
Attribute attr)
override {
767 printAttribute(attr);
769 LogicalResult printAlias(
Attribute attr)
override {
770 initializer.visit(attr);
773 LogicalResult printAlias(
Type type)
override {
774 initializer.visit(type);
779 void printOptionalLocationSpecifier(
Location loc)
override {
789 if (elidedAttrs.empty()) {
791 printAttribute(attr.getValue());
794 llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
797 if (!elidedAttrsSet.contains(attr.getName().strref()))
798 printAttribute(attr.getValue());
800 void printOptionalAttrDictWithKeyword(
803 printOptionalAttrDict(attrs, elidedAttrs);
808 raw_ostream &getStream()
const override {
return os; }
812 void printFloat(
const APFloat &)
override {}
813 void printAffineMapOfSSAIds(AffineMapAttr,
ValueRange)
override {}
816 void increaseIndent()
override {}
817 void decreaseIndent()
override {}
818 void printOperand(
Value)
override {}
819 void printOperand(
Value, raw_ostream &os)
override {
828 void printSymbolName(StringRef)
override {}
829 void printSuccessor(
Block *)
override {}
837 AliasInitializer &initializer;
840 mutable llvm::raw_null_ostream os;
845 explicit DummyAliasDialectAsmPrinter(AliasInitializer &initializer,
848 : initializer(initializer), canBeDeferred(canBeDeferred),
849 childIndices(childIndices) {}
854 template <
typename T,
typename... PrintArgs>
855 size_t printAndVisitNestedAliases(T value, PrintArgs &&...printArgs) {
856 printAndVisitNestedAliasesImpl(value, printArgs...);
857 return maxAliasDepth;
863 void printAndVisitNestedAliasesImpl(
Attribute attr,
bool elideType) {
864 if (!isa<BuiltinDialect>(attr.
getDialect())) {
868 }
else if (llvm::isa<AffineMapAttr, DenseArrayAttr, FloatAttr, IntegerAttr,
869 IntegerSetAttr, UnitAttr>(attr)) {
871 }
else if (
auto distinctAttr = dyn_cast<DistinctAttr>(attr)) {
872 printAttribute(distinctAttr.getReferencedAttr());
873 }
else if (
auto dictAttr = dyn_cast<DictionaryAttr>(attr)) {
875 printAttribute(nestedAttr.getName());
876 printAttribute(nestedAttr.getValue());
878 }
else if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr)) {
879 for (
Attribute nestedAttr : arrayAttr.getValue())
880 printAttribute(nestedAttr);
881 }
else if (
auto typeAttr = dyn_cast<TypeAttr>(attr)) {
883 }
else if (
auto locAttr = dyn_cast<OpaqueLoc>(attr)) {
884 printAttribute(locAttr.getFallbackLocation());
885 }
else if (
auto locAttr = dyn_cast<NameLoc>(attr)) {
886 if (!isa<UnknownLoc>(locAttr.getChildLoc()))
887 printAttribute(locAttr.getChildLoc());
888 }
else if (
auto locAttr = dyn_cast<CallSiteLoc>(attr)) {
889 printAttribute(locAttr.getCallee());
890 printAttribute(locAttr.getCaller());
891 }
else if (
auto locAttr = dyn_cast<FusedLoc>(attr)) {
892 if (
Attribute metadata = locAttr.getMetadata())
893 printAttribute(metadata);
894 for (
Location nestedLoc : locAttr.getLocations())
895 printAttribute(nestedLoc);
900 if (
auto typedAttr = llvm::dyn_cast<TypedAttr>(attr)) {
901 Type attrType = typedAttr.getType();
902 if (!llvm::isa<NoneType>(attrType))
907 void printAndVisitNestedAliasesImpl(
Type type) {
912 if (
auto memrefTy = llvm::dyn_cast<MemRefType>(type)) {
914 MemRefLayoutAttrInterface layout = memrefTy.getLayout();
915 if (!llvm::isa<AffineMapAttr>(layout) || !layout.isIdentity())
916 printAttribute(memrefTy.getLayout());
917 if (memrefTy.getMemorySpace())
918 printAttribute(memrefTy.getMemorySpace());
923 auto visitFn = [&](
auto element) {
925 (void)printAlias(element);
932 recordAliasResult(initializer.visit(type, canBeDeferred));
936 void printAttribute(
Attribute attr)
override {
937 recordAliasResult(initializer.visit(attr, canBeDeferred));
939 void printAttributeWithoutType(
Attribute attr)
override {
941 initializer.visit(attr, canBeDeferred,
true));
943 LogicalResult printAlias(
Attribute attr)
override {
944 printAttribute(attr);
947 LogicalResult printAlias(
Type type)
override {
953 void recordAliasResult(std::pair<size_t, size_t> aliasDepthAndIndex) {
954 childIndices.push_back(aliasDepthAndIndex.second);
955 if (aliasDepthAndIndex.first > maxAliasDepth)
956 maxAliasDepth = aliasDepthAndIndex.first;
961 raw_ostream &getStream()
const override {
return os; }
965 void printFloat(
const APFloat &)
override {}
968 void printSymbolName(StringRef)
override {}
971 LogicalResult pushCyclicPrinting(
const void *opaquePointer)
override {
972 return success(cyclicPrintingStack.insert(opaquePointer));
975 void popCyclicPrinting()
override { cyclicPrintingStack.pop_back(); }
982 AliasInitializer &initializer;
991 size_t maxAliasDepth = 0;
994 mutable llvm::raw_null_ostream os;
1002 StringRef allowedPunctChars =
"$._-",
1003 bool allowTrailingDigit =
true) {
1004 assert(!name.empty() &&
"Shouldn't have an empty name here");
1006 auto validChar = [&](
char ch) {
1007 return llvm::isAlnum(ch) || allowedPunctChars.contains(ch);
1010 auto copyNameToBuffer = [&] {
1011 for (
char ch : name) {
1013 buffer.push_back(ch);
1015 buffer.push_back(
'_');
1017 buffer.append(llvm::utohexstr((
unsigned char)ch));
1024 if (isdigit(name[0]) || (!validChar(name[0]) && name[0] !=
' ')) {
1025 buffer.push_back(
'_');
1032 if (!allowTrailingDigit && isdigit(name.back())) {
1034 buffer.push_back(
'_');
1039 for (
char ch : name) {
1040 if (!validChar(ch)) {
1052 void AliasInitializer::initializeAliases(
1053 llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
1054 llvm::MapVector<const void *, SymbolAlias> &symbolToAlias) {
1056 unprocessedAliases = visitedSymbols.takeVector();
1057 llvm::stable_sort(unprocessedAliases, [](
const auto &lhs,
const auto &rhs) {
1058 return lhs.second < rhs.second;
1061 llvm::StringMap<unsigned> nameCounts;
1062 for (
auto &[symbol, aliasInfo] : unprocessedAliases) {
1063 if (!aliasInfo.alias)
1065 StringRef alias = *aliasInfo.alias;
1066 unsigned nameIndex = nameCounts[alias]++;
1067 symbolToAlias.insert(
1068 {symbol, SymbolAlias(alias, nameIndex, aliasInfo.isType,
1069 aliasInfo.canBeDeferred)});
1073 void AliasInitializer::initialize(
1075 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias) {
1079 DummyAliasOperationPrinter aliasPrinter(printerFlags, *
this);
1080 aliasPrinter.printCustomOrGenericOp(op);
1083 initializeAliases(aliases, attrTypeToAlias);
1086 template <
typename T,
typename... PrintArgs>
1087 std::pair<size_t, size_t> AliasInitializer::visitImpl(
1088 T value, llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
1089 bool canBeDeferred, PrintArgs &&...printArgs) {
1090 auto [it, inserted] =
1091 aliases.insert({value.getAsOpaquePointer(), InProgressAliasInfo()});
1092 size_t aliasIndex = std::distance(aliases.begin(), it);
1096 markAliasNonDeferrable(aliasIndex);
1097 return {
static_cast<size_t>(it->second.aliasDepth), aliasIndex};
1101 generateAlias(value, it->second, canBeDeferred);
1102 it->second.isType = std::is_base_of_v<Type, T>;
1103 it->second.canBeDeferred = canBeDeferred;
1107 DummyAliasDialectAsmPrinter printer(*
this, canBeDeferred, childAliases);
1108 size_t maxAliasDepth =
1109 printer.printAndVisitNestedAliases(value, printArgs...);
1112 it = std::next(aliases.begin(), aliasIndex);
1115 it->second.childIndices = std::move(childAliases);
1117 it->second.aliasDepth = maxAliasDepth + 1;
1120 return {(size_t)it->second.aliasDepth, aliasIndex};
1123 void AliasInitializer::markAliasNonDeferrable(
size_t aliasIndex) {
1124 auto *it = std::next(aliases.begin(), aliasIndex);
1128 if (!it->second.canBeDeferred)
1131 it->second.canBeDeferred =
false;
1134 for (
size_t childIndex : it->second.childIndices)
1135 markAliasNonDeferrable(childIndex);
1138 template <
typename T>
1139 void AliasInitializer::generateAlias(T symbol, InProgressAliasInfo &alias,
1140 bool canBeDeferred) {
1142 for (
const auto &interface : interfaces) {
1144 interface.getAlias(symbol, aliasOS);
1147 nameBuffer = std::move(aliasBuffer);
1148 assert(!nameBuffer.empty() &&
"expected valid alias name");
1153 if (nameBuffer.empty())
1160 name = name.copy(aliasAllocator);
1161 alias = InProgressAliasInfo(name);
1179 LogicalResult getAlias(
Attribute attr, raw_ostream &os)
const;
1183 LogicalResult getAlias(
Type ty, raw_ostream &os)
const;
1187 void printNonDeferredAliases(
AsmPrinter::Impl &p, NewLineCounter &newLine) {
1188 printAliases(p, newLine,
false);
1193 printAliases(p, newLine,
true);
1203 llvm::MapVector<const void *, SymbolAlias> attrTypeToAlias;
1206 llvm::BumpPtrAllocator aliasAllocator;
1210 void AliasState::initialize(
1213 AliasInitializer initializer(interfaces, aliasAllocator);
1214 initializer.initialize(op, printerFlags, attrTypeToAlias);
1217 LogicalResult AliasState::getAlias(
Attribute attr, raw_ostream &os)
const {
1219 if (it == attrTypeToAlias.end())
1221 it->second.print(os);
1225 LogicalResult AliasState::getAlias(
Type ty, raw_ostream &os)
const {
1227 if (it == attrTypeToAlias.end())
1229 if (!it->second.isPrinted)
1232 it->second.print(os);
1236 void AliasState::printAliases(
AsmPrinter::Impl &p, NewLineCounter &newLine,
1238 auto filterFn = [=](
const auto &aliasIt) {
1239 return aliasIt.second.canBeDeferred() == isDeferred;
1241 for (
auto &[opaqueSymbol, alias] :
1242 llvm::make_filter_range(attrTypeToAlias, filterFn)) {
1246 if (alias.isTypeAlias()) {
1249 alias.isPrinted =
true;
1276 class SSANameState {
1279 enum :
unsigned { NameSentinel = ~0U };
1282 SSANameState() =
default;
1287 void printValueID(
Value value,
bool printResultNo, raw_ostream &stream)
const;
1290 void printOperationID(
Operation *op, raw_ostream &stream)
const;
1297 BlockInfo getBlockInfo(
Block *block);
1306 void numberValuesInRegion(
Region ®ion);
1307 void numberValuesInBlock(
Block &block);
1314 void getResultIDAndNumber(
OpResult result,
Value &lookupValue,
1315 std::optional<int> &lookupResultNo)
const;
1318 void setValueName(
Value value, StringRef name);
1322 StringRef uniqueValueName(StringRef name);
1345 llvm::ScopedHashTable<StringRef, char> usedNames;
1346 llvm::BumpPtrAllocator usedNameAllocator;
1349 unsigned nextValueID = 0;
1351 unsigned nextArgumentID = 0;
1353 unsigned nextConflictID = 0;
1362 : printerFlags(printerFlags) {
1363 llvm::SaveAndRestore valueIDSaver(nextValueID);
1364 llvm::SaveAndRestore argumentIDSaver(nextArgumentID);
1365 llvm::SaveAndRestore conflictIDSaver(nextConflictID);
1370 using UsedNamesScopeTy = llvm::ScopedHashTable<StringRef, char>::ScopeTy;
1371 using NamingContext =
1372 std::tuple<Region *, unsigned, unsigned, unsigned, UsedNamesScopeTy *>;
1375 llvm::BumpPtrAllocator allocator;
1378 auto *topLevelNamesScope =
1379 new (allocator.Allocate<UsedNamesScopeTy>()) UsedNamesScopeTy(usedNames);
1383 nameContext.push_back(std::make_tuple(®ion, nextValueID, nextArgumentID,
1384 nextConflictID, topLevelNamesScope));
1386 numberValuesInOp(*op);
1388 while (!nameContext.empty()) {
1390 UsedNamesScopeTy *parentScope;
1394 std::tie(region, std::ignore, std::ignore, std::ignore, parentScope) =
1395 nameContext.pop_back_val();
1397 std::tie(region, nextValueID, nextArgumentID, nextConflictID,
1398 parentScope) = nameContext.pop_back_val();
1402 while (usedNames.getCurScope() != parentScope) {
1403 usedNames.getCurScope()->~UsedNamesScopeTy();
1404 assert((usedNames.getCurScope() !=
nullptr || parentScope ==
nullptr) &&
1405 "top level parentScope must be a nullptr");
1409 auto *curNamesScope =
new (allocator.Allocate<UsedNamesScopeTy>())
1410 UsedNamesScopeTy(usedNames);
1412 numberValuesInRegion(*region);
1416 nameContext.push_back(std::make_tuple(®ion, nextValueID,
1417 nextArgumentID, nextConflictID,
1422 while (usedNames.getCurScope() !=
nullptr)
1423 usedNames.getCurScope()->~UsedNamesScopeTy();
1426 void SSANameState::printValueID(
Value value,
bool printResultNo,
1427 raw_ostream &stream)
const {
1429 stream <<
"<<NULL VALUE>>";
1433 std::optional<int> resultNo;
1434 auto lookupValue = value;
1438 if (
OpResult result = dyn_cast<OpResult>(value))
1439 getResultIDAndNumber(result, lookupValue, resultNo);
1441 auto it = valueIDs.find(lookupValue);
1442 if (it == valueIDs.end()) {
1443 stream <<
"<<UNKNOWN SSA VALUE>>";
1448 if (it->second != NameSentinel) {
1449 stream << it->second;
1451 auto nameIt = valueNames.find(lookupValue);
1452 assert(nameIt != valueNames.end() &&
"Didn't have a name entry?");
1453 stream << nameIt->second;
1456 if (resultNo && printResultNo)
1457 stream <<
'#' << *resultNo;
1460 void SSANameState::printOperationID(
Operation *op, raw_ostream &stream)
const {
1461 auto it = operationIDs.find(op);
1462 if (it == operationIDs.end()) {
1463 stream <<
"<<UNKNOWN OPERATION>>";
1465 stream <<
'%' << it->second;
1470 auto it = opResultGroups.find(op);
1471 return it == opResultGroups.end() ?
ArrayRef<int>() : it->second;
1474 BlockInfo SSANameState::getBlockInfo(
Block *block) {
1475 auto it = blockNames.find(block);
1476 BlockInfo invalidBlock{-1,
"INVALIDBLOCK"};
1477 return it != blockNames.end() ? it->second : invalidBlock;
1480 void SSANameState::shadowRegionArgs(
Region ®ion,
ValueRange namesToUse) {
1481 assert(!region.
empty() &&
"cannot shadow arguments of an empty region");
1483 "incorrect number of names passed in");
1485 "only KnownIsolatedFromAbove ops can shadow names");
1488 for (
unsigned i = 0, e = namesToUse.size(); i != e; ++i) {
1489 auto nameToUse = namesToUse[i];
1490 if (nameToUse ==
nullptr)
1495 llvm::raw_svector_ostream nameStream(nameStr);
1496 printValueID(nameToUse,
true, nameStream);
1499 assert(valueIDs[nameToReplace] == NameSentinel);
1502 auto name = StringRef(nameStream.str()).drop_front();
1505 valueNames[nameToReplace] = name.copy(usedNameAllocator);
1509 void SSANameState::numberValuesInRegion(
Region ®ion) {
1510 auto setBlockArgNameFn = [&](
Value arg, StringRef name) {
1511 assert(!valueIDs.count(arg) &&
"arg numbered multiple times");
1512 assert(llvm::cast<BlockArgument>(arg).getOwner()->getParent() == ®ion &&
1513 "arg not defined in current region");
1514 setValueName(arg, name);
1519 if (
auto asmInterface = dyn_cast<OpAsmOpInterface>(op))
1520 asmInterface.getAsmBlockArgumentNames(region, setBlockArgNameFn);
1525 unsigned nextBlockID = 0;
1526 for (
auto &block : region) {
1529 auto blockInfoIt = blockNames.insert({&block, {-1,
""}});
1530 if (blockInfoIt.second) {
1534 llvm::raw_string_ostream(name) <<
"^bb" << nextBlockID;
1535 blockInfoIt.first->second.name = StringRef(name).copy(usedNameAllocator);
1537 blockInfoIt.first->second.ordering = nextBlockID++;
1539 numberValuesInBlock(block);
1543 void SSANameState::numberValuesInBlock(
Block &block) {
1548 llvm::raw_svector_ostream specialName(specialNameBuffer);
1550 if (valueIDs.count(arg))
1553 specialNameBuffer.resize(strlen(
"arg"));
1554 specialName << nextArgumentID++;
1556 setValueName(arg, specialName.str());
1560 for (
auto &op : block)
1561 numberValuesInOp(op);
1564 void SSANameState::numberValuesInOp(
Operation &op) {
1567 auto setResultNameFn = [&](
Value result, StringRef name) {
1568 assert(!valueIDs.count(result) &&
"result numbered multiple times");
1569 assert(result.
getDefiningOp() == &op &&
"result not defined by 'op'");
1570 setValueName(result, name);
1573 if (
int resultNo = llvm::cast<OpResult>(result).getResultNumber())
1574 resultGroups.push_back(resultNo);
1577 auto setBlockNameFn = [&](
Block *block, StringRef name) {
1579 "getAsmBlockArgumentNames callback invoked on a block not directly "
1580 "nested under the current operation");
1581 assert(!blockNames.count(block) &&
"block numbered multiple times");
1584 if (name.data() != tmpBuffer.data()) {
1585 tmpBuffer.append(name);
1586 name = tmpBuffer.str();
1588 name = name.copy(usedNameAllocator);
1589 blockNames[block] = {-1, name};
1593 if (OpAsmOpInterface asmInterface = dyn_cast<OpAsmOpInterface>(&op)) {
1594 asmInterface.getAsmBlockNames(setBlockNameFn);
1595 asmInterface.getAsmResultNames(setResultNameFn);
1600 if (numResults == 0) {
1603 if (operationIDs.try_emplace(&op, nextValueID).second)
1611 if (valueIDs.try_emplace(resultBegin, nextValueID).second)
1615 if (resultGroups.size() != 1) {
1616 llvm::array_pod_sort(resultGroups.begin(), resultGroups.end());
1617 opResultGroups.try_emplace(&op, std::move(resultGroups));
1621 void SSANameState::getResultIDAndNumber(
1623 std::optional<int> &lookupResultNo)
const {
1631 auto resultGroupIt = opResultGroups.find(owner);
1632 if (resultGroupIt == opResultGroups.end()) {
1634 lookupResultNo = resultNo;
1641 const auto *it = llvm::upper_bound(resultGroups, resultNo);
1642 int groupResultNo = 0, groupSize = 0;
1645 if (it == resultGroups.end()) {
1646 groupResultNo = resultGroups.back();
1647 groupSize =
static_cast<int>(owner->
getNumResults()) - resultGroups.back();
1650 groupResultNo = *std::prev(it);
1651 groupSize = *it - groupResultNo;
1656 lookupResultNo = resultNo - groupResultNo;
1657 lookupValue = owner->
getResult(groupResultNo);
1660 void SSANameState::setValueName(
Value value, StringRef name) {
1663 valueIDs[value] = nextValueID++;
1667 valueIDs[value] = NameSentinel;
1668 valueNames[value] = uniqueValueName(name);
1671 StringRef SSANameState::uniqueValueName(StringRef name) {
1676 if (!usedNames.count(name)) {
1677 name = name.copy(usedNameAllocator);
1683 probeName.push_back(
'_');
1685 probeName += llvm::utostr(nextConflictID++);
1686 if (!usedNames.count(probeName)) {
1687 name = probeName.str().copy(usedNameAllocator);
1690 probeName.resize(name.size() + 1);
1694 usedNames.insert(name,
char());
1704 class DistinctState {
1710 uint64_t distinctCounter = 0;
1715 uint64_t DistinctState::getId(
DistinctAttr distinctAttr) {
1716 auto [it, inserted] =
1717 distinctAttrMap.try_emplace(distinctAttr, distinctCounter);
1720 return it->getSecond();
1727 AsmParsedResourceEntry::~AsmParsedResourceEntry() =
default;
1728 AsmResourceBuilder::~AsmResourceBuilder() =
default;
1729 AsmResourceParser::~AsmResourceParser() =
default;
1730 AsmResourcePrinter::~AsmResourcePrinter() =
default;
1734 case AsmResourceEntryKind::Blob:
1736 case AsmResourceEntryKind::Bool:
1738 case AsmResourceEntryKind::String:
1741 llvm_unreachable(
"unknown AsmResourceEntryKind");
1745 std::unique_ptr<ResourceCollection> &collection = keyToResources[key.str()];
1747 collection = std::make_unique<ResourceCollection>(key);
1751 std::vector<std::unique_ptr<AsmResourcePrinter>>
1753 std::vector<std::unique_ptr<AsmResourcePrinter>> printers;
1754 for (
auto &it : keyToResources) {
1755 ResourceCollection *collection = it.second.get();
1757 return collection->buildResources(op, builder);
1759 printers.emplace_back(
1765 LogicalResult FallbackAsmResourceMap::ResourceCollection::parseResource(
1769 FailureOr<AsmResourceBlob> blob = entry.
parseAsBlob();
1772 resources.emplace_back(entry.
getKey(), std::move(*blob));
1779 resources.emplace_back(entry.
getKey(), *value);
1786 resources.emplace_back(entry.
getKey(), std::move(*str));
1793 void FallbackAsmResourceMap::ResourceCollection::buildResources(
1795 for (
const auto &entry : resources) {
1796 if (
const auto *value = std::get_if<AsmResourceBlob>(&entry.value))
1798 else if (
const auto *value = std::get_if<bool>(&entry.value))
1800 else if (
const auto *value = std::get_if<std::string>(&entry.value))
1803 llvm_unreachable(
"unknown AsmResourceEntryKind");
1817 : interfaces(op->
getContext()), nameState(op, printerFlags),
1818 printerFlags(printerFlags), locationMap(locationMap) {}
1821 : interfaces(ctx), printerFlags(printerFlags), locationMap(locationMap) {}
1825 aliasState.initialize(op, printerFlags, interfaces);
1845 return llvm::make_pointee_range(externalResourcePrinters);
1855 (*locationMap)[op] = std::make_pair(line, col);
1861 return dialectResources;
1865 return success(cyclicPrintingStack.insert(opaquePointer));
1881 AliasState aliasState;
1884 SSANameState nameState;
1887 DistinctState distinctState;
1903 template <
typename Range>
1907 [&stream](
const auto &dimSize) {
1908 if (ShapedType::isDynamic(dimSize))
1926 return printerFlags;
1930 auto parentThreadId = llvm::get_threadid();
1932 if (parentThreadId == llvm::get_threadid()) {
1934 diag.print(llvm::dbgs());
1935 llvm::dbgs() <<
"\n";
1941 if (failed(
verify(op))) {
1942 LLVM_DEBUG(llvm::dbgs()
1944 <<
"' failed to verify and will be printed in generic form\n");
1948 return printerFlags;
1967 return impl->getPrinterFlags();
1971 std::unique_ptr<AsmResourcePrinter> printer) {
1972 impl->externalResourcePrinters.emplace_back(std::move(printer));
1977 return impl->getDialectResources();
1985 : os(os), state(state), printerFlags(state.getPrinterFlags()) {}
1993 printLocation(loc, allowAlias);
1999 if (!isTopLevel && succeeded(state.getAliasState().getAlias(loc, os)))
2003 .Case<OpaqueLoc>([&](OpaqueLoc loc) {
2004 printLocationInternal(loc.getFallbackLocation(), pretty);
2006 .Case<UnknownLoc>([&](UnknownLoc loc) {
2012 .Case<FileLineColLoc>([&](FileLineColLoc loc) {
2014 os << loc.getFilename().getValue();
2016 printEscapedString(loc.getFilename());
2017 os <<
':' << loc.getLine() <<
':' << loc.getColumn();
2019 .Case<NameLoc>([&](NameLoc loc) {
2020 printEscapedString(loc.getName());
2023 auto childLoc = loc.getChildLoc();
2024 if (!llvm::isa<UnknownLoc>(childLoc)) {
2026 printLocationInternal(childLoc, pretty);
2030 .Case<CallSiteLoc>([&](CallSiteLoc loc) {
2035 printLocationInternal(callee, pretty);
2037 if (llvm::isa<NameLoc>(callee)) {
2038 if (llvm::isa<FileLineColLoc>(caller)) {
2041 os << newLine <<
" at ";
2044 os << newLine <<
" at ";
2049 printLocationInternal(caller, pretty);
2053 .Case<FusedLoc>([&](
FusedLoc loc) {
2056 if (
Attribute metadata = loc.getMetadata()) {
2064 [&](Location loc) { printLocationInternal(loc, pretty); },
2065 [&]() { os << ", "; });
2068 .Default([&](LocationAttr loc) {
2069 // Assumes that this is a dialect-specific attribute and prints it
2071 printAttribute(loc);
2077 static void printFloatValue(const APFloat &apValue, raw_ostream &os,
2078 bool *printedHex = nullptr) {
2079 // We would like to output the FP constant value in exponential notation,
2080 // but we cannot do this if doing so will lose precision. Check here to
2081 // make sure that we only output it in exponential format if we can parse
2082 // the value back and get the same value.
2083 bool isInf = apValue.isInfinity();
2084 bool isNaN = apValue.isNaN();
2085 if (!isInf && !isNaN) {
2086 SmallString<128> strValue;
2087 apValue.toString(strValue, /*FormatPrecision=*/6, /*FormatMaxPadding=*/0,
2088 /*TruncateZero=*/false);
2090 // Check to make sure that the stringized number is not some string like
2091 // "Inf" or NaN, that atof will accept, but the lexer will not. Check
2092 // that the string matches the "[-+]?[0-9]" regex.
2093 assert(((strValue[0] >= '0
' && strValue[0] <= '9') ||
2094 ((strValue[0] ==
'-' || strValue[0] ==
'+') &&
2095 (strValue[1] >=
'0' && strValue[1] <=
'9'))) &&
2096 "[-+]?[0-9] regex does not match!");
2100 if (APFloat(apValue.getSemantics(), strValue).bitwiseIsEqual(apValue)) {
2108 apValue.toString(strValue);
2111 if (strValue.str().contains(
'.')) {
2122 APInt apInt = apValue.bitcastToAPInt();
2123 apInt.toString(str, 16,
false,
2130 return printLocationInternal(loc,
true,
true);
2134 printLocationInternal(loc,
false,
true);
2142 state.getDialectResources()[resource.
getDialect()].insert(resource);
2150 if (symName.empty() || !isalpha(symName.front()))
2155 symName = symName.drop_while(
2156 [](
char c) {
return llvm::isAlnum(c) || c ==
'.' || c ==
'_'; });
2157 if (symName.empty())
2162 return symName.front() ==
'<' && symName.back() ==
'>';
2167 StringRef dialectName, StringRef symString) {
2168 os << symPrefix << dialectName;
2173 os <<
'.' << symString;
2177 os << '<' << symString << '>
';
2181 static bool isBareIdentifier(StringRef name) {
2182 // By making this unsigned, the value passed in to isalnum will always be
2183 // in the range 0-255. This is important when building with MSVC because
2184 // its implementation will assert. This situation can arise when dealing
2185 // with UTF-8 multibyte characters.
2186 if (name.empty() || (!isalpha(name[0]) && name[0] != '_
'))
2188 return llvm::all_of(name.drop_front(), [](unsigned char c) {
2189 return isalnum(c) || c == '_
' || c == '$
' || c == '.
';
2195 static void printKeywordOrString(StringRef keyword, raw_ostream &os) {
2196 // If it can be represented as a bare identifier, write it directly.
2197 if (isBareIdentifier(keyword)) {
2202 // Otherwise, output the keyword wrapped in quotes with proper escaping.
2204 printEscapedString(keyword, os);
2211 static void printSymbolReference(StringRef symbolRef, raw_ostream &os) {
2212 if (symbolRef.empty()) {
2213 os << "@<<INVALID EMPTY SYMBOL>>
";
2217 printKeywordOrString(symbolRef, os);
2220 // Print out a valid ElementsAttr that is succinct and can represent any
2221 // potential shape/type, for use when eliding a large ElementsAttr.
2223 // We choose to use a dense resource ElementsAttr literal with conspicuous
2224 // content to hopefully alert readers to the fact that this has been elided.
2225 static void printElidedElementsAttr(raw_ostream &os) {
2226 os << R"(dense_resource<__elided__>)
";
2229 LogicalResult AsmPrinter::Impl::printAlias(Attribute attr) {
2230 return state.getAliasState().getAlias(attr, os);
2233 LogicalResult AsmPrinter::Impl::printAlias(Type type) {
2234 return state.getAliasState().getAlias(type, os);
2237 void AsmPrinter::Impl::printAttribute(Attribute attr,
2238 AttrTypeElision typeElision) {
2240 os << "<<NULL ATTRIBUTE>>
";
2244 // Try to print an alias for this attribute.
2245 if (succeeded(printAlias(attr)))
2247 return printAttributeImpl(attr, typeElision);
2250 void AsmPrinter::Impl::printAttributeImpl(Attribute attr,
2251 AttrTypeElision typeElision) {
2252 if (!isa<BuiltinDialect>(attr.getDialect())) {
2253 printDialectAttribute(attr);
2254 } else if (auto opaqueAttr = llvm::dyn_cast<OpaqueAttr>(attr)) {
2255 printDialectSymbol(os, "#
", opaqueAttr.getDialectNamespace(),
2256 opaqueAttr.getAttrData());
2257 } else if (llvm::isa<UnitAttr>(attr)) {
2260 } else if (auto distinctAttr = llvm::dyn_cast<DistinctAttr>(attr)) {
2261 os << "distinct[
" << state.getDistinctState().getId(distinctAttr) << "]<
";
2262 if (!llvm::isa<UnitAttr>(distinctAttr.getReferencedAttr())) {
2263 printAttribute(distinctAttr.getReferencedAttr());
2267 } else if (auto dictAttr = llvm::dyn_cast<DictionaryAttr>(attr)) {
2269 interleaveComma(dictAttr.getValue(),
2270 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2273 } else if (auto intAttr = llvm::dyn_cast<IntegerAttr>(attr)) {
2274 Type intType = intAttr.getType();
2275 if (intType.isSignlessInteger(1)) {
2276 os << (intAttr.getValue().getBoolValue() ? "true" : "false");
2278 // Boolean integer attributes always elides the type.
2282 // Only print attributes as unsigned if they are explicitly unsigned or are
2283 // signless 1-bit values. Indexes, signed values, and multi-bit signless
2284 // values print as signed.
2286 intType.isUnsignedInteger() || intType.isSignlessInteger(1);
2287 intAttr.getValue().print(os, !isUnsigned);
2289 // IntegerAttr elides the type if I64.
2290 if (typeElision == AttrTypeElision::May && intType.isSignlessInteger(64))
2293 } else if (auto floatAttr = llvm::dyn_cast<FloatAttr>(attr)) {
2294 bool printedHex = false;
2295 printFloatValue(floatAttr.getValue(), os, &printedHex);
2297 // FloatAttr elides the type if F64.
2298 if (typeElision == AttrTypeElision::May && floatAttr.getType().isF64() &&
2302 } else if (auto strAttr = llvm::dyn_cast<StringAttr>(attr)) {
2303 printEscapedString(strAttr.getValue());
2305 } else if (auto arrayAttr = llvm::dyn_cast<ArrayAttr>(attr)) {
2307 interleaveComma(arrayAttr.getValue(), [&](Attribute attr) {
2308 printAttribute(attr, AttrTypeElision::May);
2312 } else if (auto affineMapAttr = llvm::dyn_cast<AffineMapAttr>(attr)) {
2313 os << "affine_map<
";
2314 affineMapAttr.getValue().print(os);
2317 // AffineMap always elides the type.
2320 } else if (auto integerSetAttr = llvm::dyn_cast<IntegerSetAttr>(attr)) {
2321 os << "affine_set<
";
2322 integerSetAttr.getValue().print(os);
2325 // IntegerSet always elides the type.
2328 } else if (auto typeAttr = llvm::dyn_cast<TypeAttr>(attr)) {
2329 printType(typeAttr.getValue());
2331 } else if (auto refAttr = llvm::dyn_cast<SymbolRefAttr>(attr)) {
2332 printSymbolReference(refAttr.getRootReference().getValue(), os);
2333 for (FlatSymbolRefAttr nestedRef : refAttr.getNestedReferences()) {
2335 printSymbolReference(nestedRef.getValue(), os);
2338 } else if (auto intOrFpEltAttr =
2339 llvm::dyn_cast<DenseIntOrFPElementsAttr>(attr)) {
2340 if (printerFlags.shouldElideElementsAttr(intOrFpEltAttr)) {
2341 printElidedElementsAttr(os);
2344 printDenseIntOrFPElementsAttr(intOrFpEltAttr, /*allowHex=*/true);
2348 } else if (auto strEltAttr = llvm::dyn_cast<DenseStringElementsAttr>(attr)) {
2349 if (printerFlags.shouldElideElementsAttr(strEltAttr)) {
2350 printElidedElementsAttr(os);
2353 printDenseStringElementsAttr(strEltAttr);
2357 } else if (auto sparseEltAttr = llvm::dyn_cast<SparseElementsAttr>(attr)) {
2358 if (printerFlags.shouldElideElementsAttr(sparseEltAttr.getIndices()) ||
2359 printerFlags.shouldElideElementsAttr(sparseEltAttr.getValues())) {
2360 printElidedElementsAttr(os);
2363 DenseIntElementsAttr indices = sparseEltAttr.getIndices();
2364 if (indices.getNumElements() != 0) {
2365 printDenseIntOrFPElementsAttr(indices, /*allowHex=*/false);
2367 printDenseElementsAttr(sparseEltAttr.getValues(), /*allowHex=*/true);
2371 } else if (auto stridedLayoutAttr = llvm::dyn_cast<StridedLayoutAttr>(attr)) {
2372 stridedLayoutAttr.print(os);
2373 } else if (auto denseArrayAttr = llvm::dyn_cast<DenseArrayAttr>(attr)) {
2375 printType(denseArrayAttr.getElementType());
2376 if (!denseArrayAttr.empty()) {
2378 printDenseArrayAttr(denseArrayAttr);
2382 } else if (auto resourceAttr =
2383 llvm::dyn_cast<DenseResourceElementsAttr>(attr)) {
2384 os << "dense_resource<
";
2385 printResourceHandle(resourceAttr.getRawHandle());
2387 } else if (auto locAttr = llvm::dyn_cast<LocationAttr>(attr)) {
2388 printLocation(locAttr);
2390 llvm::report_fatal_error("Unknown builtin attribute
");
2392 // Don't print the type if we must elide it, or if it is a None type.
2393 if (typeElision != AttrTypeElision::Must) {
2394 if (auto typedAttr = llvm::dyn_cast<TypedAttr>(attr)) {
2395 Type attrType = typedAttr.getType();
2396 if (!llvm::isa<NoneType>(attrType)) {
2398 printType(attrType);
2405 static void printDenseIntElement(const APInt &value, raw_ostream &os,
2407 if (type.isInteger(1))
2408 os << (value.getBoolValue() ? "
true" : "false");
2410 value.print(os, !type.isUnsignedInteger());
2414 printDenseElementsAttrImpl(bool isSplat, ShapedType type, raw_ostream &os,
2415 function_ref<void(unsigned)> printEltFn) {
2416 // Special case for 0-d and splat tensors.
2418 return printEltFn(0);
2420 // Special case for degenerate tensors.
2421 auto numElements = type.getNumElements();
2422 if (numElements == 0)
2425 // We use a mixed-radix counter to iterate through the shape. When we bump a
2426 // non-least-significant digit, we emit a close bracket. When we next emit an
2427 // element we re-open all closed brackets.
2429 // The mixed-radix counter, with radices in 'shape'.
2430 int64_t rank = type.getRank();
2431 SmallVector<unsigned, 4> counter(rank, 0);
2432 // The number of brackets that have been opened and not closed.
2433 unsigned openBrackets = 0;
2435 auto shape = type.getShape();
2436 auto bumpCounter = [&] {
2437 // Bump the least significant digit.
2438 ++counter[rank - 1];
2439 // Iterate backwards bubbling back the increment.
2440 for (unsigned i = rank - 1; i > 0; --i)
2441 if (counter[i] >= shape[i]) {
2442 // Index 'i' is rolled over. Bump (i-1) and close a bracket.
2450 for (unsigned idx = 0, e = numElements; idx != e; ++idx) {
2453 while (openBrackets++ < rank)
2455 openBrackets = rank;
2459 while (openBrackets-- > 0)
2463 void AsmPrinter::Impl::printDenseElementsAttr(DenseElementsAttr attr,
2465 if (auto stringAttr = llvm::dyn_cast<DenseStringElementsAttr>(attr))
2466 return printDenseStringElementsAttr(stringAttr);
2468 printDenseIntOrFPElementsAttr(llvm::cast<DenseIntOrFPElementsAttr>(attr),
2472 void AsmPrinter::Impl::printDenseIntOrFPElementsAttr(
2473 DenseIntOrFPElementsAttr attr, bool allowHex) {
2474 auto type = attr.getType();
2475 auto elementType = type.getElementType();
2477 // Check to see if we should format this attribute as a hex string.
2478 if (allowHex && printerFlags.shouldPrintElementsAttrWithHex(attr)) {
2479 ArrayRef<char> rawData = attr.getRawData();
2480 if (llvm::endianness::native == llvm::endianness::big) {
2481 // Convert endianess in big-endian(BE) machines. `rawData` is BE in BE
2482 // machines. It is converted here to print in LE format.
2483 SmallVector<char, 64> outDataVec(rawData.size());
2484 MutableArrayRef<char> convRawData(outDataVec);
2485 DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
2486 rawData, convRawData, type);
2487 printHexString(convRawData);
2489 printHexString(rawData);
2495 if (ComplexType complexTy = llvm::dyn_cast<ComplexType>(elementType)) {
2496 Type complexElementType = complexTy.getElementType();
2497 // Note: The if and else below had a common lambda function which invoked
2498 // printDenseElementsAttrImpl. This lambda was hitting a bug in gcc 9.1,9.2
2499 // and hence was replaced.
2500 if (llvm::isa<IntegerType>(complexElementType)) {
2501 auto valueIt = attr.value_begin<std::complex<APInt>>();
2502 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2503 auto complexValue = *(valueIt + index);
2505 printDenseIntElement(complexValue.real(), os, complexElementType);
2507 printDenseIntElement(complexValue.imag(), os, complexElementType);
2511 auto valueIt = attr.value_begin<std::complex<APFloat>>();
2512 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2513 auto complexValue = *(valueIt + index);
2515 printFloatValue(complexValue.real(), os);
2517 printFloatValue(complexValue.imag(), os);
2521 } else if (elementType.isIntOrIndex()) {
2522 auto valueIt = attr.value_begin<APInt>();
2523 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2524 printDenseIntElement(*(valueIt + index), os, elementType);
2527 assert(llvm::isa<FloatType>(elementType) && "unexpected element type
");
2528 auto valueIt = attr.value_begin<APFloat>();
2529 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2530 printFloatValue(*(valueIt + index), os);
2535 void AsmPrinter::Impl::printDenseStringElementsAttr(
2536 DenseStringElementsAttr attr) {
2537 ArrayRef<StringRef> data = attr.getRawStringData();
2538 auto printFn = [&](unsigned index) { printEscapedString(data[index]); };
2539 printDenseElementsAttrImpl(attr.isSplat(), attr.getType(), os, printFn);
2542 void AsmPrinter::Impl::printDenseArrayAttr(DenseArrayAttr attr) {
2543 Type type = attr.getElementType();
2544 unsigned bitwidth = type.isInteger(1) ? 8 : type.getIntOrFloatBitWidth();
2545 unsigned byteSize = bitwidth / 8;
2546 ArrayRef<char> data = attr.getRawData();
2548 auto printElementAt = [&](unsigned i) {
2549 APInt value(bitwidth, 0);
2551 llvm::LoadIntFromMemory(
2552 value, reinterpret_cast<const uint8_t *>(data.begin() + byteSize * i),
2555 // Print the data as-is or as a float.
2556 if (type.isIntOrIndex()) {
2557 printDenseIntElement(value, getStream(), type);
2559 APFloat fltVal(llvm::cast<FloatType>(type).getFloatSemantics(), value);
2560 printFloatValue(fltVal, getStream());
2563 llvm::interleaveComma(llvm::seq<unsigned>(0, attr.size()), getStream(),
2567 void AsmPrinter::Impl::printType(Type type) {
2569 os << "<<NULL TYPE>>
";
2573 // Try to print an alias for this type.
2574 if (succeeded(printAlias(type)))
2576 return printTypeImpl(type);
2579 void AsmPrinter::Impl::printTypeImpl(Type type) {
2580 TypeSwitch<Type>(type)
2581 .Case<OpaqueType>([&](OpaqueType opaqueTy) {
2582 printDialectSymbol(os, "!
", opaqueTy.getDialectNamespace(),
2583 opaqueTy.getTypeData());
2585 .Case<IndexType>([&](Type) { os << "index
"; })
2586 .Case<Float4E2M1FNType>([&](Type) { os << "f4E2M1FN
"; })
2587 .Case<Float6E2M3FNType>([&](Type) { os << "f6E2M3FN
"; })
2588 .Case<Float6E3M2FNType>([&](Type) { os << "f6E3M2FN
"; })
2589 .Case<Float8E5M2Type>([&](Type) { os << "f8E5M2
"; })
2590 .Case<Float8E4M3Type>([&](Type) { os << "f8E4M3
"; })
2591 .Case<Float8E4M3FNType>([&](Type) { os << "f8E4M3FN
"; })
2592 .Case<Float8E5M2FNUZType>([&](Type) { os << "f8E5M2FNUZ
"; })
2593 .Case<Float8E4M3FNUZType>([&](Type) { os << "f8E4M3FNUZ
"; })
2594 .Case<Float8E4M3B11FNUZType>([&](Type) { os << "f8E4M3B11FNUZ
"; })
2595 .Case<Float8E3M4Type>([&](Type) { os << "f8E3M4
"; })
2596 .Case<Float8E8M0FNUType>([&](Type) { os << "f8E8M0FNU
"; })
2597 .Case<BFloat16Type>([&](Type) { os << "bf16"; })
2598 .Case<Float16Type>([&](Type) { os << "f16"; })
2599 .Case<FloatTF32Type>([&](Type) { os << "tf32
"; })
2600 .Case<Float32Type>([&](Type) { os << "f32
"; })
2601 .Case<Float64Type>([&](Type) { os << "f64
"; })
2602 .Case<Float80Type>([&](Type) { os << "f80
"; })
2603 .Case<Float128Type>([&](Type) { os << "f128
"; })
2604 .Case<IntegerType>([&](IntegerType integerTy) {
2605 if (integerTy.isSigned())
2607 else if (integerTy.isUnsigned())
2609 os << 'i' << integerTy.getWidth();
2611 .Case<FunctionType>([&](FunctionType funcTy) {
2613 interleaveComma(funcTy.getInputs(), [&](Type ty) { printType(ty); });
2615 ArrayRef<Type> results = funcTy.getResults();
2616 if (results.size() == 1 && !llvm::isa<FunctionType>(results[0])) {
2617 printType(results[0]);
2620 interleaveComma(results, [&](Type ty) { printType(ty); });
2624 .Case<VectorType>([&](VectorType vectorTy) {
2625 auto scalableDims = vectorTy.getScalableDims();
2627 auto vShape = vectorTy.getShape();
2628 unsigned lastDim = vShape.size();
2629 unsigned dimIdx = 0;
2630 for (dimIdx = 0; dimIdx < lastDim; dimIdx++) {
2631 if (!scalableDims.empty() && scalableDims[dimIdx])
2633 os << vShape[dimIdx];
2634 if (!scalableDims.empty() && scalableDims[dimIdx])
2638 printType(vectorTy.getElementType());
2641 .Case<RankedTensorType>([&](RankedTensorType tensorTy) {
2643 printDimensionList(tensorTy.getShape());
2644 if (!tensorTy.getShape().empty())
2646 printType(tensorTy.getElementType());
2647 // Only print the encoding attribute value if set.
2648 if (tensorTy.getEncoding()) {
2650 printAttribute(tensorTy.getEncoding());
2654 .Case<UnrankedTensorType>([&](UnrankedTensorType tensorTy) {
2656 printType(tensorTy.getElementType());
2659 .Case<MemRefType>([&](MemRefType memrefTy) {
2661 printDimensionList(memrefTy.getShape());
2662 if (!memrefTy.getShape().empty())
2664 printType(memrefTy.getElementType());
2665 MemRefLayoutAttrInterface layout = memrefTy.getLayout();
2666 if (!llvm::isa<AffineMapAttr>(layout) || !layout.isIdentity()) {
2668 printAttribute(memrefTy.getLayout(), AttrTypeElision::May);
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<UnrankedMemRefType>([&](UnrankedMemRefType memrefTy) {
2679 printType(memrefTy.getElementType());
2680 // Only print the memory space if it is the non-default one.
2681 if (memrefTy.getMemorySpace()) {
2683 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2687 .Case<ComplexType>([&](ComplexType complexTy) {
2689 printType(complexTy.getElementType());
2692 .Case<TupleType>([&](TupleType tupleTy) {
2694 interleaveComma(tupleTy.getTypes(),
2695 [&](Type type) { printType(type); });
2698 .Case<NoneType>([&](Type) { os << "none
"; })
2699 .Default([&](Type type) { return printDialectType(type); });
2702 void AsmPrinter::Impl::printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
2703 ArrayRef<StringRef> elidedAttrs,
2705 // If there are no attributes, then there is nothing to be done.
2709 // Functor used to print a filtered attribute list.
2710 auto printFilteredAttributesFn = [&](auto filteredAttrs) {
2711 // Print the 'attributes' keyword if necessary.
2713 os << " attributes
";
2715 // Otherwise, print them all out in braces.
2717 interleaveComma(filteredAttrs,
2718 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2722 // If no attributes are elided, we can directly print with no filtering.
2723 if (elidedAttrs.empty())
2724 return printFilteredAttributesFn(attrs);
2726 // Otherwise, filter out any attributes that shouldn't be included.
2727 llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
2729 auto filteredAttrs = llvm::make_filter_range(attrs, [&](NamedAttribute attr) {
2730 return !elidedAttrsSet.contains(attr.getName().strref());
2732 if (!filteredAttrs.empty())
2733 printFilteredAttributesFn(filteredAttrs);
2735 void AsmPrinter::Impl::printNamedAttribute(NamedAttribute attr) {
2736 // Print the name without quotes if possible.
2737 ::printKeywordOrString(attr.getName().strref(), os);
2739 // Pretty printing elides the attribute value for unit attributes.
2740 if (llvm::isa<UnitAttr>(attr.getValue()))
2744 printAttribute(attr.getValue());
2747 void AsmPrinter::Impl::printDialectAttribute(Attribute attr) {
2748 auto &dialect = attr.getDialect();
2750 // Ask the dialect to serialize the attribute to a string.
2751 std::string attrName;
2753 llvm::raw_string_ostream attrNameStr(attrName);
2754 Impl subPrinter(attrNameStr, state);
2755 DialectAsmPrinter printer(subPrinter);
2756 dialect.printAttribute(attr, printer);
2758 printDialectSymbol(os, "#
", dialect.getNamespace(), attrName);
2761 void AsmPrinter::Impl::printDialectType(Type type) {
2762 auto &dialect = type.getDialect();
2764 // Ask the dialect to serialize the type to a string.
2765 std::string typeName;
2767 llvm::raw_string_ostream typeNameStr(typeName);
2768 Impl subPrinter(typeNameStr, state);
2769 DialectAsmPrinter printer(subPrinter);
2770 dialect.printType(type, printer);
2772 printDialectSymbol(os, "!
", dialect.getNamespace(), typeName);
2775 void AsmPrinter::Impl::printEscapedString(StringRef str) {
2777 llvm::printEscapedString(str, os);
2782 os <<
"\"0x" << llvm::toHex(str) <<
"\"";
2785 printHexString(StringRef(data.data(), data.size()));
2789 return state.pushCyclicPrinting(opaquePointer);
2805 assert(
impl &&
"expected AsmPrinter::getStream to be overriden");
2806 return impl->getStream();
2811 assert(
impl &&
"expected AsmPrinter::printFloat to be overriden");
2816 assert(
impl &&
"expected AsmPrinter::printType to be overriden");
2817 impl->printType(type);
2821 assert(
impl &&
"expected AsmPrinter::printAttribute to be overriden");
2822 impl->printAttribute(attr);
2826 assert(
impl &&
"expected AsmPrinter::printAlias to be overriden");
2827 return impl->printAlias(attr);
2831 assert(
impl &&
"expected AsmPrinter::printAlias to be overriden");
2832 return impl->printAlias(type);
2837 "expected AsmPrinter::printAttributeWithoutType to be overriden");
2842 assert(
impl &&
"expected AsmPrinter::printKeywordOrString to be overriden");
2847 assert(
impl &&
"expected AsmPrinter::printString to be overriden");
2849 printEscapedString(keyword,
getStream());
2854 assert(
impl &&
"expected AsmPrinter::printSymbolName to be overriden");
2859 assert(
impl &&
"expected AsmPrinter::printResourceHandle to be overriden");
2860 impl->printResourceHandle(resource);
2868 return impl->pushCyclicPrinting(opaquePointer);
2879 printAffineExprInternal(expr, BindingStrength::Weak, printValueName);
2885 const char *binopSpelling =
nullptr;
2888 unsigned pos = cast<AffineSymbolExpr>(expr).getPosition();
2890 printValueName(pos,
true);
2896 unsigned pos = cast<AffineDimExpr>(expr).getPosition();
2898 printValueName(pos,
false);
2904 os << cast<AffineConstantExpr>(expr).getValue();
2907 binopSpelling =
" + ";
2910 binopSpelling =
" * ";
2913 binopSpelling =
" floordiv ";
2916 binopSpelling =
" ceildiv ";
2919 binopSpelling =
" mod ";
2923 auto binOp = cast<AffineBinaryOpExpr>(expr);
2929 if (enclosingTightness == BindingStrength::Strong)
2933 auto rhsConst = dyn_cast<AffineConstantExpr>(rhsExpr);
2935 rhsConst.getValue() == -1) {
2937 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
2938 if (enclosingTightness == BindingStrength::Strong)
2943 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
2945 os << binopSpelling;
2946 printAffineExprInternal(rhsExpr, BindingStrength::Strong, printValueName);
2948 if (enclosingTightness == BindingStrength::Strong)
2954 if (enclosingTightness == BindingStrength::Strong)
2959 if (
auto rhs = dyn_cast<AffineBinaryOpExpr>(rhsExpr)) {
2962 if (
auto rrhs = dyn_cast<AffineConstantExpr>(rrhsExpr)) {
2963 if (rrhs.getValue() == -1) {
2964 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
2968 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
2971 printAffineExprInternal(rhs.getLHS(), BindingStrength::Weak,
2975 if (enclosingTightness == BindingStrength::Strong)
2980 if (rrhs.getValue() < -1) {
2981 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
2984 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
2986 os <<
" * " << -rrhs.getValue();
2987 if (enclosingTightness == BindingStrength::Strong)
2996 if (
auto rhsConst = dyn_cast<AffineConstantExpr>(rhsExpr)) {
2997 if (rhsConst.getValue() < 0) {
2998 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
2999 os <<
" - " << -rhsConst.getValue();
3000 if (enclosingTightness == BindingStrength::Strong)
3006 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
3009 printAffineExprInternal(rhsExpr, BindingStrength::Weak, printValueName);
3011 if (enclosingTightness == BindingStrength::Strong)
3016 printAffineExprInternal(expr, BindingStrength::Weak);
3017 isEq ? os <<
" == 0" : os <<
" >= 0";
3023 for (
int i = 0; i < (int)map.
getNumDims() - 1; ++i)
3024 os <<
'd' << i <<
", ";
3033 os <<
's' << i <<
", ";
3042 [&](
AffineExpr expr) { printAffineExpr(expr); });
3049 for (
unsigned i = 1; i < set.
getNumDims(); ++i)
3050 os <<
'd' << i - 1 <<
", ";
3059 os <<
's' << i <<
", ";
3068 for (
int i = 1; i < numConstraints; ++i) {
3072 if (numConstraints >= 1)
3073 printAffineConstraint(set.
getConstraint(numConstraints - 1),
3074 set.
isEq(numConstraints - 1));
3089 explicit OperationPrinter(raw_ostream &os,
AsmStateImpl &state)
3093 void printTopLevelOperation(
Operation *op);
3097 void printFullOpWithIndentAndLoc(
Operation *op);
3103 void printCustomOrGenericOp(
Operation *op)
override;
3105 void printGenericOp(
Operation *op,
bool printOpName)
override;
3108 void printBlockName(
Block *block);
3113 void print(
Block *block,
bool printBlockArgs =
true,
3114 bool printBlockTerminator =
true);
3117 void printValueID(
Value value,
bool printResultNo =
true,
3118 raw_ostream *streamOverride =
nullptr)
const;
3122 raw_ostream *streamOverride =
nullptr)
const;
3130 void printOptionalLocationSpecifier(
Location loc)
override {
3131 printTrailingLocation(loc);
3138 os.indent(currentIndent);
3142 void increaseIndent()
override { currentIndent += indentWidth; }
3145 void decreaseIndent()
override { currentIndent -= indentWidth; }
3154 bool omitType =
false)
override;
3157 void printOperand(
Value value)
override { printValueID(value); }
3158 void printOperand(
Value value, raw_ostream &os)
override {
3159 printValueID(value,
true, &os);
3167 void printOptionalAttrDictWithKeyword(
3175 void printSuccessor(
Block *successor)
override;
3179 void printSuccessorAndUseList(
Block *successor,
3184 bool printBlockTerminators,
bool printEmptyBlock)
override;
3191 state.getSSANameState().shadowRegionArgs(region, namesToUse);
3196 void printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3211 void printValueUsers(
Value value);
3215 void printUserIDs(
Operation *user,
bool prefixComma =
false);
3223 using PrintFn =
function_ref<void(StringRef, ValueFn)>;
3225 ResourceBuilder(PrintFn printFn) : printFn(printFn) {}
3226 ~ResourceBuilder()
override =
default;
3228 void buildBool(StringRef key,
bool data)
final {
3229 printFn(key, [&](raw_ostream &os) { os << (data ?
"true" :
"false"); });
3232 void buildString(StringRef key, StringRef data)
final {
3233 printFn(key, [&](raw_ostream &os) {
3235 llvm::printEscapedString(data, os);
3241 uint32_t dataAlignment)
final {
3242 printFn(key, [&](raw_ostream &os) {
3244 llvm::support::ulittle32_t dataAlignmentLE(dataAlignment);
3246 << llvm::toHex(StringRef(
reinterpret_cast<char *
>(&dataAlignmentLE),
3247 sizeof(dataAlignment)))
3248 << llvm::toHex(StringRef(data.data(), data.size())) <<
"\"";
3257 void printFileMetadataDictionary(
Operation *op);
3263 void printResourceFileMetadata(
function_ref<
void()> checkAddMetadataDict,
3274 const static unsigned indentWidth = 2;
3277 unsigned currentIndent = 0;
3281 void OperationPrinter::printTopLevelOperation(
Operation *op) {
3283 state.getAliasState().printNonDeferredAliases(*
this, newLine);
3286 printFullOpWithIndentAndLoc(op);
3290 state.getAliasState().printDeferredAliases(*
this, newLine);
3293 printFileMetadataDictionary(op);
3296 void OperationPrinter::printFileMetadataDictionary(
Operation *op) {
3297 bool sawMetadataEntry =
false;
3298 auto checkAddMetadataDict = [&] {
3299 if (!std::exchange(sawMetadataEntry,
true))
3300 os << newLine <<
"{-#" << newLine;
3304 printResourceFileMetadata(checkAddMetadataDict, op);
3307 if (sawMetadataEntry)
3308 os << newLine <<
"#-}" << newLine;
3311 void OperationPrinter::printResourceFileMetadata(
3314 bool hadResource =
false;
3315 bool needResourceComma =
false;
3316 bool needEntryComma =
false;
3317 auto processProvider = [&](StringRef dictName, StringRef name,
auto &provider,
3318 auto &&...providerArgs) {
3319 bool hadEntry =
false;
3320 auto printFn = [&](StringRef key, ResourceBuilder::ValueFn valueFn) {
3321 checkAddMetadataDict();
3323 auto printFormatting = [&]() {
3325 if (!std::exchange(hadResource,
true)) {
3326 if (needResourceComma)
3327 os <<
"," << newLine;
3328 os <<
" " << dictName <<
"_resources: {" << newLine;
3331 if (!std::exchange(hadEntry,
true)) {
3333 os <<
"," << newLine;
3334 os <<
" " << name <<
": {" << newLine;
3336 os <<
"," << newLine;
3340 std::optional<uint64_t> charLimit =
3342 if (charLimit.has_value()) {
3343 std::string resourceStr;
3344 llvm::raw_string_ostream ss(resourceStr);
3348 if (resourceStr.size() > charLimit.value())
3352 os <<
" " << key <<
": " << resourceStr;
3355 os <<
" " << key <<
": ";
3359 ResourceBuilder entryBuilder(printFn);
3360 provider.buildResources(op, providerArgs..., entryBuilder);
3362 needEntryComma |= hadEntry;
3364 os << newLine <<
" }";
3370 auto &dialectResources = state.getDialectResources();
3371 StringRef name = interface.getDialect()->getNamespace();
3372 auto it = dialectResources.find(interface.getDialect());
3373 if (it != dialectResources.end())
3374 processProvider(
"dialect", name, interface, it->second);
3376 processProvider(
"dialect", name, interface,
3380 os << newLine <<
" }";
3384 needEntryComma =
false;
3385 needResourceComma = hadResource;
3386 hadResource =
false;
3387 for (
const auto &printer : state.getResourcePrinters())
3388 processProvider(
"external", printer.getName(), printer);
3390 os << newLine <<
" }";
3398 void OperationPrinter::printRegionArgument(
BlockArgument arg,
3406 printOptionalAttrDict(argAttrs);
3408 printTrailingLocation(arg.
getLoc(),
false);
3411 void OperationPrinter::printFullOpWithIndentAndLoc(
Operation *op) {
3413 state.registerOperationLocation(op, newLine.curLine, currentIndent);
3415 os.indent(currentIndent);
3417 printTrailingLocation(op->
getLoc());
3419 printUsersComment(op);
3422 void OperationPrinter::printFullOp(
Operation *op) {
3424 auto printResultGroup = [&](
size_t resultNo,
size_t resultCount) {
3425 printValueID(op->
getResult(resultNo),
false);
3426 if (resultCount > 1)
3427 os <<
':' << resultCount;
3431 ArrayRef<int> resultGroups = state.getSSANameState().getOpResultGroups(op);
3432 if (!resultGroups.empty()) {
3435 interleaveComma(llvm::seq<int>(0, resultGroups.size() - 1), [&](
int i) {
3436 printResultGroup(resultGroups[i],
3437 resultGroups[i + 1] - resultGroups[i]);
3440 printResultGroup(resultGroups.back(), numResults - resultGroups.back());
3443 printResultGroup(0, numResults);
3449 printCustomOrGenericOp(op);
3452 void OperationPrinter::printUsersComment(
Operation *op) {
3456 printOperationID(op);
3457 }
else if (numResults && op->
use_empty()) {
3459 }
else if (numResults && !op->
use_empty()) {
3462 unsigned usedInNResults = 0;
3463 unsigned usedInNOperations = 0;
3466 if (userSet.insert(user).second) {
3467 ++usedInNOperations;
3468 usedInNResults += user->getNumResults();
3473 bool exactlyOneUniqueUse =
3474 usedInNResults <= 1 && usedInNOperations <= 1 && numResults == 1;
3475 os <<
" // " << (exactlyOneUniqueUse ?
"user" :
"users") <<
": ";
3476 bool shouldPrintBrackets = numResults > 1;
3477 auto printOpResult = [&](
OpResult opResult) {
3478 if (shouldPrintBrackets)
3480 printValueUsers(opResult);
3481 if (shouldPrintBrackets)
3485 interleaveComma(op->
getResults(), printOpResult);
3489 void OperationPrinter::printUsersComment(
BlockArgument arg) {
3495 os <<
" is used by ";
3496 printValueUsers(arg);
3501 void OperationPrinter::printValueUsers(
Value value) {
3509 if (userSet.insert(user).second)
3510 printUserIDs(user, index);
3514 void OperationPrinter::printUserIDs(
Operation *user,
bool prefixComma) {
3519 printOperationID(user);
3522 [
this](
Value result) { printValueID(result); });
3526 void OperationPrinter::printCustomOrGenericOp(
Operation *op) {
3532 opInfo->printAssembly(op, *
this, defaultDialectStack.back());
3537 if (
auto opPrinter = dialect->getOperationPrinter(op)) {
3542 if (name.count(
'.') == 1)
3543 name.consume_front((defaultDialectStack.back() +
".").str());
3547 opPrinter(op, *
this);
3554 printGenericOp(op,
true);
3557 void OperationPrinter::printGenericOp(
Operation *op,
bool printOpName) {
3561 interleaveComma(op->
getOperands(), [&](
Value value) { printValueID(value); });
3568 [&](
Block *successor) { printBlockName(successor); });
3580 if (op->getNumRegions() != 0) {
3582 interleaveComma(op->getRegions(), [&](Region ®ion) {
3583 printRegion(region, /*printEntryBlockArgs=*/true,
3584 /*printBlockTerminators=*/true, /*printEmptyBlock=*/true);
3589 printOptionalAttrDict(op->getPropertiesStorage()
3590 ? llvm::to_vector(op->getDiscardableAttrs())
3593 // Print the type signature of the operation.
3595 printFunctionalType(op);
3598 void OperationPrinter::printBlockName(Block *block) {
3599 os << state.getSSANameState().getBlockInfo(block).name;
3602 void OperationPrinter::print(Block *block, bool printBlockArgs,
3603 bool printBlockTerminator) {
3604 // Print the block label and argument list if requested.
3605 if (printBlockArgs) {
3606 os.indent(currentIndent);
3607 printBlockName(block);
3609 // Print the argument list if non-empty.
3610 if (!block->args_empty()) {
3612 interleaveComma(block->getArguments(), [&](BlockArgument arg) {
3615 printType(arg.getType());
3616 // TODO: We should allow location aliases on block arguments.
3617 printTrailingLocation(arg.getLoc(), /*allowAlias*/ false);
3623 // Print out some context information about the predecessors of this block.
3624 if (!block->getParent()) {
3625 os << " // block is not in a region!";
3626 } else if (block->hasNoPredecessors()) {
3627 if (!block->isEntryBlock())
3628 os << " // no predecessors";
3629 } else if (auto *pred = block->getSinglePredecessor()) {
3631 printBlockName(pred);
3633 // We want to print the predecessors in a stable order, not in
3634 // whatever order the use-list is in, so gather and sort them.
3635 SmallVector<BlockInfo, 4> predIDs;
3636 for (auto *pred : block->getPredecessors())
3637 predIDs.push_back(state.getSSANameState().getBlockInfo(pred));
3638 llvm::sort(predIDs, [](BlockInfo lhs, BlockInfo rhs) {
3639 return lhs.ordering < rhs.ordering;
3642 os << " // " << predIDs.size() << " preds: ";
3644 interleaveComma(predIDs, [&](BlockInfo pred) { os << pred.name; });
3649 currentIndent += indentWidth;
3651 if (printerFlags.shouldPrintValueUsers()) {
3652 for (BlockArgument arg : block->getArguments()) {
3653 os.indent(currentIndent);
3654 printUsersComment(arg);
3658 bool hasTerminator =
3659 !block->empty() && block->back().hasTrait<OpTrait::IsTerminator>();
3660 auto range = llvm::make_range(
3662 std::prev(block->end(),
3663 (!hasTerminator || printBlockTerminator) ? 0 : 1));
3664 for (auto &op : range) {
3665 printFullOpWithIndentAndLoc(&op);
3668 currentIndent -= indentWidth;
3671 void OperationPrinter::printValueID(Value value, bool printResultNo,
3672 raw_ostream *streamOverride) const {
3673 state.getSSANameState().printValueID(value, printResultNo,
3674 streamOverride ? *streamOverride : os);
3677 void OperationPrinter::printOperationID(Operation *op,
3678 raw_ostream *streamOverride) const {
3679 state.getSSANameState().printOperationID(op, streamOverride ? *streamOverride
3683 void OperationPrinter::printSuccessor(Block *successor) {
3684 printBlockName(successor);
3687 void OperationPrinter::printSuccessorAndUseList(Block *successor,
3688 ValueRange succOperands) {
3689 printBlockName(successor);
3690 if (succOperands.empty())
3694 interleaveComma(succOperands,
3695 [this](Value operand) { printValueID(operand); });
3697 interleaveComma(succOperands,
3698 [this](Value operand) { printType(operand.getType()); });
3702 void OperationPrinter::printRegion(Region ®ion, bool printEntryBlockArgs,
3703 bool printBlockTerminators,
3704 bool printEmptyBlock) {
3705 if (printerFlags.shouldSkipRegions()) {
3709 os << "{" << newLine;
3710 if (!region.empty()) {
3711 auto restoreDefaultDialect =
3712 llvm::make_scope_exit([&]() { defaultDialectStack.pop_back(); });
3713 if (auto iface = dyn_cast<OpAsmOpInterface>(region.getParentOp()))
3714 defaultDialectStack.push_back(iface.getDefaultDialect());
3716 defaultDialectStack.push_back("");
3718 auto *entryBlock = ®ion.front();
3719 // Force printing the block header if printEmptyBlock is set and the block
3720 // is empty or if printEntryBlockArgs is set and there are arguments to
3722 bool shouldAlwaysPrintBlockHeader =
3723 (printEmptyBlock && entryBlock->empty()) ||
3724 (printEntryBlockArgs && entryBlock->getNumArguments() != 0);
3725 print(entryBlock, shouldAlwaysPrintBlockHeader, printBlockTerminators);
3726 for (auto &b : llvm::drop_begin(region.getBlocks(), 1))
3729 os.indent(currentIndent) << "}";
3732 void OperationPrinter::printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3733 ValueRange operands) {
3735 os << "<<NULL AFFINE MAP>>";
3738 AffineMap map = mapAttr.getValue();
3739 unsigned numDims = map.getNumDims();
3740 auto printValueName = [&](unsigned pos, bool isSymbol) {
3741 unsigned index = isSymbol ? numDims + pos : pos;
3742 assert(index < operands.size());
3745 printValueID(operands[index]);
3750 interleaveComma(map.getResults(), [&](AffineExpr expr) {
3751 printAffineExpr(expr, printValueName);
3755 void OperationPrinter::printAffineExprOfSSAIds(AffineExpr expr,
3756 ValueRange dimOperands,
3757 ValueRange symOperands) {
3758 auto printValueName = [&](unsigned pos, bool isSymbol) {
3760 return printValueID(dimOperands[pos]);
3762 printValueID(symOperands[pos]);
3765 printAffineExpr(expr, printValueName);
3768 //===----------------------------------------------------------------------===//
3769 // print and dump methods
3770 //===----------------------------------------------------------------------===//
3772 void Attribute::print(raw_ostream &os, bool elideType) const {
3774 os << "<<NULL ATTRIBUTE>>";
3778 AsmState state(getContext());
3779 print(os, state, elideType);
3781 void Attribute::print(raw_ostream &os, AsmState &state, bool elideType) const {
3782 using AttrTypeElision = AsmPrinter::Impl::AttrTypeElision;
3783 AsmPrinter::Impl(os, state.getImpl())
3784 .printAttribute(*this, elideType ? AttrTypeElision::Must
3785 : AttrTypeElision::Never);
3788 void Attribute::dump() const {
3789 print(llvm::errs());
3790 llvm::errs() << "\n";
3793 void Attribute::printStripped(raw_ostream &os, AsmState &state) const {
3795 os << "<<NULL ATTRIBUTE>>";
3799 AsmPrinter::Impl subPrinter(os, state.getImpl());
3800 if (succeeded(subPrinter.printAlias(*this)))
3803 auto &dialect = this->getDialect();
3804 uint64_t posPrior = os.tell();
3805 DialectAsmPrinter printer(subPrinter);
3806 dialect.printAttribute(*this, printer);
3807 if (posPrior != os.tell())
3810 // Fallback to printing with prefix if the above failed to write anything
3811 // to the output stream.
3814 void Attribute::printStripped(raw_ostream &os) const {
3816 os << "<<NULL ATTRIBUTE>>";
3820 AsmState state(getContext());
3821 printStripped(os, state);
3824 void Type::print(raw_ostream &os) const {
3826 os << "<<NULL TYPE>>";
3830 AsmState state(getContext());
3833 void Type::print(raw_ostream &os, AsmState &state) const {
3834 AsmPrinter::Impl(os, state.getImpl()).printType(*this);
3837 void Type::dump() const {
3838 print(llvm::errs());
3839 llvm::errs() << "\n";
3842 void AffineMap::dump() const {
3843 print(llvm::errs());
3844 llvm::errs() << "\n";
3847 void IntegerSet::dump() const {
3848 print(llvm::errs());
3849 llvm::errs() << "\n";
3852 void AffineExpr::print(raw_ostream &os) const {
3854 os << "<<NULL AFFINE EXPR>>";
3857 AsmState state(getContext());
3858 AsmPrinter::Impl(os, state.getImpl()).printAffineExpr(*this);
3861 void AffineExpr::dump() const {
3862 print(llvm::errs());
3863 llvm::errs() << "\n";
3866 void AffineMap::print(raw_ostream &os) const {
3868 os << "<<NULL AFFINE MAP>>";
3871 AsmState state(getContext());
3872 AsmPrinter::Impl(os, state.getImpl()).printAffineMap(*this);
3875 void IntegerSet::print(raw_ostream &os) const {
3876 AsmState state(getContext());
3877 AsmPrinter::Impl(os, state.getImpl()).printIntegerSet(*this);
3880 void Value::print(raw_ostream &os) const { print(os, OpPrintingFlags()); }
3881 void Value::print(raw_ostream &os, const OpPrintingFlags &flags) const {
3883 os << "<<NULL VALUE>>";
3887 if (auto *op = getDefiningOp())
3888 return op->print(os, flags);
3889 // TODO: Improve BlockArgument print'ing.
3891 os <<
"<block argument> of type '" << arg.
getType()
3896 os <<
"<<NULL VALUE>>";
3900 if (
auto *op = getDefiningOp())
3901 return op->
print(os, state);
3905 os <<
"<block argument> of type '" << arg.
getType()
3910 print(llvm::errs());
3911 llvm::errs() <<
"\n";
3919 state.getImpl().getSSANameState().printValueID(*
this,
true,
3942 if (
auto result = llvm::dyn_cast<OpResult>(*
this)) {
3945 op = llvm::cast<BlockArgument>(*this).getOwner()->
getParentOp();
3947 os <<
"<<UNKNOWN SSA VALUE>>";
3953 printAsOperand(os, state);
3963 OperationPrinter printer(os, state.getImpl());
3964 if (!getParent() && !state.getPrinterFlags().shouldUseLocalScope()) {
3965 state.getImpl().initializeAliases(
this);
3966 printer.printTopLevelOperation(
this);
3968 printer.printFullOpWithIndentAndLoc(
this);
3974 llvm::errs() <<
"\n";
3980 os <<
"<<UNLINKED BLOCK>>\n";
3991 OperationPrinter(os, state.getImpl()).print(
this);
4000 os <<
"<<UNLINKED BLOCK>>\n";
4004 printAsOperand(os, state);
4007 OperationPrinter printer(os, state.getImpl());
4008 printer.printBlockName(
this);
4023 if (dimensions.empty())
4026 if (dimensions.empty())
4036 <<
"Failed parsing dimension list.";
4047 <<
"Failed parsing dimension list.";
4049 if (shapeArr.empty()) {
4051 <<
"Failed parsing dimension list. Did you mean an empty list? It "
4052 "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)
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.