29 #include "llvm/ADT/APFloat.h"
30 #include "llvm/ADT/DenseMap.h"
31 #include "llvm/ADT/MapVector.h"
32 #include "llvm/ADT/STLExtras.h"
33 #include "llvm/ADT/ScopeExit.h"
34 #include "llvm/ADT/ScopedHashTable.h"
35 #include "llvm/ADT/SetVector.h"
36 #include "llvm/ADT/SmallString.h"
37 #include "llvm/ADT/StringExtras.h"
38 #include "llvm/ADT/StringSet.h"
39 #include "llvm/ADT/TypeSwitch.h"
40 #include "llvm/Support/CommandLine.h"
41 #include "llvm/Support/Debug.h"
42 #include "llvm/Support/Endian.h"
43 #include "llvm/Support/Regex.h"
44 #include "llvm/Support/SaveAndRestore.h"
45 #include "llvm/Support/Threading.h"
46 #include "llvm/Support/raw_ostream.h"
54 #define DEBUG_TYPE "mlir-asm-printer"
74 [&]() {
return parseType(result.emplace_back()); });
92 auto &os = getStream();
96 *this << (operand ? operand.getType() : Type());
112 *this << (result ? result.getType() : Type());
124 #include "mlir/IR/OpAsmInterface.cpp.inc"
128 return entry.
emitError() <<
"unknown 'resource' key '" << entry.
getKey()
129 <<
"' for dialect '" << getDialect()->getNamespace()
141 struct AsmPrinterOptions {
142 llvm::cl::opt<int64_t> printElementsAttrWithHexIfLarger{
143 "mlir-print-elementsattrs-with-hex-if-larger",
145 "Print DenseElementsAttrs with a hex string that have "
146 "more elements than the given upper limit (use -1 to disable)")};
148 llvm::cl::opt<unsigned> elideElementsAttrIfLarger{
149 "mlir-elide-elementsattrs-if-larger",
150 llvm::cl::desc(
"Elide ElementsAttrs with \"...\" that have "
151 "more elements than the given upper limit")};
153 llvm::cl::opt<unsigned> elideResourceStringsIfLarger{
154 "mlir-elide-resource-strings-if-larger",
156 "Elide printing value of resources if string is too long in chars.")};
158 llvm::cl::opt<bool> printDebugInfoOpt{
159 "mlir-print-debuginfo", llvm::cl::init(
false),
160 llvm::cl::desc(
"Print debug info in MLIR output")};
162 llvm::cl::opt<bool> printPrettyDebugInfoOpt{
163 "mlir-pretty-debuginfo", llvm::cl::init(
false),
164 llvm::cl::desc(
"Print pretty debug info in MLIR output")};
168 llvm::cl::opt<bool> printGenericOpFormOpt{
169 "mlir-print-op-generic", llvm::cl::init(
false),
170 llvm::cl::desc(
"Print the generic op form"), llvm::cl::Hidden};
172 llvm::cl::opt<bool> assumeVerifiedOpt{
173 "mlir-print-assume-verified", llvm::cl::init(
false),
174 llvm::cl::desc(
"Skip op verification when using custom printers"),
177 llvm::cl::opt<bool> printLocalScopeOpt{
178 "mlir-print-local-scope", llvm::cl::init(
false),
179 llvm::cl::desc(
"Print with local scope and inline information (eliding "
180 "aliases for attributes, types, and locations")};
182 llvm::cl::opt<bool> printValueUsers{
183 "mlir-print-value-users", llvm::cl::init(
false),
185 "Print users of operation results and block arguments as a comment")};
189 static llvm::ManagedStatic<AsmPrinterOptions>
clOptions;
200 : printDebugInfoFlag(false), printDebugInfoPrettyFormFlag(false),
201 printGenericOpFormFlag(false), skipRegionsFlag(false),
202 assumeVerifiedFlag(false), printLocalScope(false),
203 printValueUsersFlag(false) {
207 if (
clOptions->elideElementsAttrIfLarger.getNumOccurrences())
208 elementsAttrElementLimit =
clOptions->elideElementsAttrIfLarger;
209 if (
clOptions->elideResourceStringsIfLarger.getNumOccurrences())
210 resourceStringCharLimit =
clOptions->elideResourceStringsIfLarger;
211 printDebugInfoFlag =
clOptions->printDebugInfoOpt;
212 printDebugInfoPrettyFormFlag =
clOptions->printPrettyDebugInfoOpt;
213 printGenericOpFormFlag =
clOptions->printGenericOpFormOpt;
214 assumeVerifiedFlag =
clOptions->assumeVerifiedOpt;
215 printLocalScope =
clOptions->printLocalScopeOpt;
216 printValueUsersFlag =
clOptions->printValueUsers;
225 elementsAttrElementLimit = largeElementLimit;
231 resourceStringCharLimit = largeResourceLimit;
239 printDebugInfoFlag = enable;
240 printDebugInfoPrettyFormFlag = prettyForm;
246 printGenericOpFormFlag = enable;
252 skipRegionsFlag = skip;
258 assumeVerifiedFlag =
true;
266 printLocalScope =
true;
272 printValueUsersFlag =
true;
278 return elementsAttrElementLimit &&
279 *elementsAttrElementLimit < int64_t(attr.getNumElements()) &&
280 !llvm::isa<SplatElementsAttr>(attr);
285 return elementsAttrElementLimit;
290 return resourceStringCharLimit;
295 return printDebugInfoFlag;
300 return printDebugInfoPrettyFormFlag;
305 return printGenericOpFormFlag;
313 return assumeVerifiedFlag;
321 return printValueUsersFlag;
329 if (
clOptions->printElementsAttrWithHexIfLarger.getNumOccurrences()) {
331 if (
clOptions->printElementsAttrWithHexIfLarger == -1)
333 return numElements >
clOptions->printElementsAttrWithHexIfLarger;
338 return numElements > 100;
349 struct NewLineCounter {
350 unsigned curLine = 1;
353 static raw_ostream &
operator<<(raw_ostream &os, NewLineCounter &newLine) {
372 template <
typename Container,
typename UnaryFunctor>
374 llvm::interleaveComma(c,
os, eachFn);
420 function_ref<
void(
unsigned,
bool)> printValueName =
nullptr);
431 bool withKeyword =
false);
435 bool isTopLevel =
false);
471 function_ref<
void(
unsigned,
bool)> printValueName =
nullptr);
495 SymbolAlias(StringRef name, uint32_t suffixIndex,
bool isType,
497 : name(name), suffixIndex(suffixIndex), isType(isType),
498 isDeferrable(isDeferrable) {}
501 void print(raw_ostream &os)
const {
502 os << (isType ?
"!" :
"#") << name;
508 bool isTypeAlias()
const {
return isType; }
511 bool canBeDeferred()
const {
return isDeferrable; }
517 uint32_t suffixIndex : 30;
521 bool isDeferrable : 1;
527 class AliasInitializer {
531 llvm::BumpPtrAllocator &aliasAllocator)
532 : interfaces(interfaces), aliasAllocator(aliasAllocator),
533 aliasOS(aliasBuffer) {}
536 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias);
544 std::pair<size_t, size_t>
visit(
Attribute attr,
bool canBeDeferred =
false,
545 bool elideType =
false) {
546 return visitImpl(attr, aliases, canBeDeferred, elideType);
553 std::pair<size_t, size_t>
visit(
Type type,
bool canBeDeferred =
false) {
554 return visitImpl(type, aliases, canBeDeferred);
558 struct InProgressAliasInfo {
559 InProgressAliasInfo()
560 : aliasDepth(0), isType(false), canBeDeferred(false) {}
561 InProgressAliasInfo(StringRef alias,
bool isType,
bool canBeDeferred)
562 : alias(alias), aliasDepth(1), isType(isType),
563 canBeDeferred(canBeDeferred) {}
565 bool operator<(
const InProgressAliasInfo &rhs)
const {
567 if (aliasDepth != rhs.aliasDepth)
568 return aliasDepth < rhs.aliasDepth;
569 if (isType != rhs.isType)
571 return alias < rhs.alias;
576 std::optional<StringRef> alias;
579 unsigned aliasDepth : 30;
583 bool canBeDeferred : 1;
593 template <
typename T,
typename... PrintArgs>
594 std::pair<size_t, size_t>
596 llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
597 bool canBeDeferred, PrintArgs &&...printArgs);
600 void markAliasNonDeferrable(
size_t aliasIndex);
604 template <
typename T>
605 void generateAlias(T symbol, InProgressAliasInfo &alias,
bool canBeDeferred);
609 static void initializeAliases(
610 llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
611 llvm::MapVector<const void *, SymbolAlias> &symbolToAlias);
617 llvm::BumpPtrAllocator &aliasAllocator;
620 llvm::MapVector<const void *, InProgressAliasInfo> aliases;
624 llvm::raw_svector_ostream aliasOS;
632 class DummyAliasOperationPrinter :
private OpAsmPrinter {
634 explicit DummyAliasOperationPrinter(
const OpPrintingFlags &printerFlags,
635 AliasInitializer &initializer)
636 : printerFlags(printerFlags), initializer(initializer) {}
640 void printCustomOrGenericOp(
Operation *op)
override {
642 if (printerFlags.shouldPrintDebugInfo())
643 initializer.visit(op->
getLoc(),
true);
646 if (!printerFlags.shouldPrintGenericOpForm()) {
657 void printGenericOp(
Operation *op,
bool printOpName =
true)
override {
659 if (!printerFlags.shouldSkipRegions()) {
673 printAttribute(attr.getValue());
679 void print(
Block *block,
bool printBlockArgs =
true,
680 bool printBlockTerminator =
true) {
683 if (printBlockArgs) {
688 if (printerFlags.shouldPrintDebugInfo())
690 initializer.visit(arg.getLoc(),
false);
698 auto range = llvm::make_range(
700 std::prev(block->
end(),
701 (!hasTerminator || printBlockTerminator) ? 0 : 1));
703 printCustomOrGenericOp(&op);
708 bool printBlockTerminators,
709 bool printEmptyBlock =
false)
override {
712 if (printerFlags.shouldSkipRegions()) {
717 auto *entryBlock = ®ion.
front();
718 print(entryBlock, printEntryBlockArgs, printBlockTerminators);
719 for (
Block &b : llvm::drop_begin(region, 1))
724 bool omitType)
override {
727 if (printerFlags.shouldPrintDebugInfo())
729 initializer.visit(arg.
getLoc(),
false);
733 void printType(
Type type)
override { initializer.visit(type); }
736 void printAttribute(
Attribute attr)
override { initializer.visit(attr); }
737 void printAttributeWithoutType(
Attribute attr)
override {
738 printAttribute(attr);
741 initializer.visit(attr);
745 initializer.visit(type);
750 void printOptionalLocationSpecifier(
Location loc)
override {
760 if (elidedAttrs.empty()) {
762 printAttribute(attr.getValue());
765 llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
768 if (!elidedAttrsSet.contains(attr.getName().strref()))
769 printAttribute(attr.getValue());
771 void printOptionalAttrDictWithKeyword(
774 printOptionalAttrDict(attrs, elidedAttrs);
779 raw_ostream &getStream()
const override {
return os; }
783 void printFloat(
const APFloat &)
override {}
784 void printAffineMapOfSSAIds(AffineMapAttr,
ValueRange)
override {}
787 void increaseIndent()
override {}
788 void decreaseIndent()
override {}
789 void printOperand(
Value)
override {}
790 void printOperand(
Value, raw_ostream &os)
override {
799 void printSymbolName(StringRef)
override {}
800 void printSuccessor(
Block *)
override {}
808 AliasInitializer &initializer;
811 mutable llvm::raw_null_ostream os;
816 explicit DummyAliasDialectAsmPrinter(AliasInitializer &initializer,
819 : initializer(initializer), canBeDeferred(canBeDeferred),
820 childIndices(childIndices) {}
825 template <
typename T,
typename... PrintArgs>
826 size_t printAndVisitNestedAliases(T value, PrintArgs &&...printArgs) {
827 printAndVisitNestedAliasesImpl(value, printArgs...);
828 return maxAliasDepth;
834 void printAndVisitNestedAliasesImpl(
Attribute attr,
bool elideType) {
835 if (!isa<BuiltinDialect>(attr.
getDialect())) {
839 }
else if (llvm::isa<AffineMapAttr, DenseArrayAttr, FloatAttr, IntegerAttr,
840 IntegerSetAttr, UnitAttr>(attr)) {
842 }
else if (
auto distinctAttr = dyn_cast<DistinctAttr>(attr)) {
843 printAttribute(distinctAttr.getReferencedAttr());
844 }
else if (
auto dictAttr = dyn_cast<DictionaryAttr>(attr)) {
846 printAttribute(nestedAttr.getName());
847 printAttribute(nestedAttr.getValue());
849 }
else if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr)) {
850 for (
Attribute nestedAttr : arrayAttr.getValue())
851 printAttribute(nestedAttr);
852 }
else if (
auto typeAttr = dyn_cast<TypeAttr>(attr)) {
854 }
else if (
auto locAttr = dyn_cast<OpaqueLoc>(attr)) {
855 printAttribute(locAttr.getFallbackLocation());
856 }
else if (
auto locAttr = dyn_cast<NameLoc>(attr)) {
857 if (!isa<UnknownLoc>(locAttr.getChildLoc()))
858 printAttribute(locAttr.getChildLoc());
859 }
else if (
auto locAttr = dyn_cast<CallSiteLoc>(attr)) {
860 printAttribute(locAttr.getCallee());
861 printAttribute(locAttr.getCaller());
862 }
else if (
auto locAttr = dyn_cast<FusedLoc>(attr)) {
863 if (
Attribute metadata = locAttr.getMetadata())
864 printAttribute(metadata);
865 for (
Location nestedLoc : locAttr.getLocations())
866 printAttribute(nestedLoc);
871 if (
auto typedAttr = llvm::dyn_cast<TypedAttr>(attr)) {
872 Type attrType = typedAttr.getType();
873 if (!llvm::isa<NoneType>(attrType))
878 void printAndVisitNestedAliasesImpl(
Type type) {
883 if (
auto memrefTy = llvm::dyn_cast<MemRefType>(type)) {
885 MemRefLayoutAttrInterface layout = memrefTy.getLayout();
886 if (!llvm::isa<AffineMapAttr>(layout) || !layout.isIdentity())
887 printAttribute(memrefTy.getLayout());
888 if (memrefTy.getMemorySpace())
889 printAttribute(memrefTy.getMemorySpace());
894 auto visitFn = [&](
auto element) {
896 (void)printAlias(element);
903 recordAliasResult(initializer.visit(type, canBeDeferred));
907 void printAttribute(
Attribute attr)
override {
908 recordAliasResult(initializer.visit(attr, canBeDeferred));
910 void printAttributeWithoutType(
Attribute attr)
override {
912 initializer.visit(attr, canBeDeferred,
true));
915 printAttribute(attr);
924 void recordAliasResult(std::pair<size_t, size_t> aliasDepthAndIndex) {
925 childIndices.push_back(aliasDepthAndIndex.second);
926 if (aliasDepthAndIndex.first > maxAliasDepth)
927 maxAliasDepth = aliasDepthAndIndex.first;
932 raw_ostream &getStream()
const override {
return os; }
936 void printFloat(
const APFloat &)
override {}
939 void printSymbolName(StringRef)
override {}
942 LogicalResult pushCyclicPrinting(
const void *opaquePointer)
override {
943 return success(cyclicPrintingStack.insert(opaquePointer));
946 void popCyclicPrinting()
override { cyclicPrintingStack.pop_back(); }
953 AliasInitializer &initializer;
962 size_t maxAliasDepth = 0;
965 mutable llvm::raw_null_ostream os;
973 StringRef allowedPunctChars =
"$._-",
974 bool allowTrailingDigit =
true) {
975 assert(!name.empty() &&
"Shouldn't have an empty name here");
977 auto copyNameToBuffer = [&] {
978 for (
char ch : name) {
979 if (llvm::isAlnum(ch) || allowedPunctChars.contains(ch))
980 buffer.push_back(ch);
982 buffer.push_back(
'_');
984 buffer.append(llvm::utohexstr((
unsigned char)ch));
991 if (isdigit(name[0])) {
992 buffer.push_back(
'_');
999 if (!allowTrailingDigit && isdigit(name.back())) {
1001 buffer.push_back(
'_');
1006 for (
char ch : name) {
1007 if (!llvm::isAlnum(ch) && !allowedPunctChars.contains(ch)) {
1019 void AliasInitializer::initializeAliases(
1020 llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
1021 llvm::MapVector<const void *, SymbolAlias> &symbolToAlias) {
1023 unprocessedAliases = visitedSymbols.takeVector();
1024 llvm::stable_sort(unprocessedAliases, [](
const auto &lhs,
const auto &rhs) {
1025 return lhs.second < rhs.second;
1028 llvm::StringMap<unsigned> nameCounts;
1029 for (
auto &[symbol, aliasInfo] : unprocessedAliases) {
1030 if (!aliasInfo.alias)
1032 StringRef alias = *aliasInfo.alias;
1033 unsigned nameIndex = nameCounts[alias]++;
1034 symbolToAlias.insert(
1035 {symbol, SymbolAlias(alias, nameIndex, aliasInfo.isType,
1036 aliasInfo.canBeDeferred)});
1040 void AliasInitializer::initialize(
1042 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias) {
1046 DummyAliasOperationPrinter aliasPrinter(printerFlags, *
this);
1047 aliasPrinter.printCustomOrGenericOp(op);
1050 initializeAliases(aliases, attrTypeToAlias);
1053 template <
typename T,
typename... PrintArgs>
1054 std::pair<size_t, size_t> AliasInitializer::visitImpl(
1055 T value, llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
1056 bool canBeDeferred, PrintArgs &&...printArgs) {
1057 auto [it, inserted] =
1058 aliases.insert({value.getAsOpaquePointer(), InProgressAliasInfo()});
1059 size_t aliasIndex = std::distance(aliases.begin(), it);
1063 markAliasNonDeferrable(aliasIndex);
1064 return {
static_cast<size_t>(it->second.aliasDepth), aliasIndex};
1068 generateAlias(value, it->second, canBeDeferred);
1072 DummyAliasDialectAsmPrinter printer(*
this, canBeDeferred, childAliases);
1073 size_t maxAliasDepth =
1074 printer.printAndVisitNestedAliases(value, printArgs...);
1077 it = std::next(aliases.begin(), aliasIndex);
1080 it->second.childIndices = std::move(childAliases);
1082 it->second.aliasDepth = maxAliasDepth + 1;
1085 return {(size_t)it->second.aliasDepth, aliasIndex};
1088 void AliasInitializer::markAliasNonDeferrable(
size_t aliasIndex) {
1089 auto it = std::next(aliases.begin(), aliasIndex);
1093 if (!it->second.canBeDeferred)
1096 it->second.canBeDeferred =
false;
1099 for (
size_t childIndex : it->second.childIndices)
1100 markAliasNonDeferrable(childIndex);
1103 template <
typename T>
1104 void AliasInitializer::generateAlias(T symbol, InProgressAliasInfo &alias,
1105 bool canBeDeferred) {
1107 for (
const auto &interface : interfaces) {
1109 interface.getAlias(symbol, aliasOS);
1112 nameBuffer = std::move(aliasBuffer);
1113 assert(!nameBuffer.empty() &&
"expected valid alias name");
1118 if (nameBuffer.empty())
1125 name = name.copy(aliasAllocator);
1126 alias = InProgressAliasInfo(name, std::is_base_of_v<Type, T>,
1153 void printNonDeferredAliases(
AsmPrinter::Impl &p, NewLineCounter &newLine) {
1154 printAliases(p, newLine,
false);
1159 printAliases(p, newLine,
true);
1169 llvm::MapVector<const void *, SymbolAlias> attrTypeToAlias;
1172 llvm::BumpPtrAllocator aliasAllocator;
1176 void AliasState::initialize(
1179 AliasInitializer initializer(interfaces, aliasAllocator);
1180 initializer.initialize(op, printerFlags, attrTypeToAlias);
1185 if (it == attrTypeToAlias.end())
1187 it->second.print(os);
1193 if (it == attrTypeToAlias.end())
1196 it->second.print(os);
1200 void AliasState::printAliases(
AsmPrinter::Impl &p, NewLineCounter &newLine,
1202 auto filterFn = [=](
const auto &aliasIt) {
1203 return aliasIt.second.canBeDeferred() == isDeferred;
1205 for (
auto &[opaqueSymbol, alias] :
1206 llvm::make_filter_range(attrTypeToAlias, filterFn)) {
1210 if (alias.isTypeAlias()) {
1243 class SSANameState {
1246 enum :
unsigned { NameSentinel = ~0U };
1249 SSANameState() =
default;
1254 void printValueID(
Value value,
bool printResultNo, raw_ostream &stream)
const;
1257 void printOperationID(
Operation *op, raw_ostream &stream)
const;
1264 BlockInfo getBlockInfo(
Block *block);
1273 void numberValuesInRegion(
Region ®ion);
1274 void numberValuesInBlock(
Block &block);
1281 void getResultIDAndNumber(
OpResult result,
Value &lookupValue,
1282 std::optional<int> &lookupResultNo)
const;
1285 void setValueName(
Value value, StringRef name);
1289 StringRef uniqueValueName(StringRef name);
1312 llvm::ScopedHashTable<StringRef, char> usedNames;
1313 llvm::BumpPtrAllocator usedNameAllocator;
1316 unsigned nextValueID = 0;
1318 unsigned nextArgumentID = 0;
1320 unsigned nextConflictID = 0;
1329 : printerFlags(printerFlags) {
1330 llvm::SaveAndRestore valueIDSaver(nextValueID);
1331 llvm::SaveAndRestore argumentIDSaver(nextArgumentID);
1332 llvm::SaveAndRestore conflictIDSaver(nextConflictID);
1337 using UsedNamesScopeTy = llvm::ScopedHashTable<StringRef, char>::ScopeTy;
1338 using NamingContext =
1339 std::tuple<Region *, unsigned, unsigned, unsigned, UsedNamesScopeTy *>;
1342 llvm::BumpPtrAllocator allocator;
1345 auto *topLevelNamesScope =
1346 new (allocator.Allocate<UsedNamesScopeTy>()) UsedNamesScopeTy(usedNames);
1350 nameContext.push_back(std::make_tuple(®ion, nextValueID, nextArgumentID,
1351 nextConflictID, topLevelNamesScope));
1353 numberValuesInOp(*op);
1355 while (!nameContext.empty()) {
1357 UsedNamesScopeTy *parentScope;
1358 std::tie(region, nextValueID, nextArgumentID, nextConflictID, parentScope) =
1359 nameContext.pop_back_val();
1363 while (usedNames.getCurScope() != parentScope) {
1364 usedNames.getCurScope()->~UsedNamesScopeTy();
1365 assert((usedNames.getCurScope() !=
nullptr || parentScope ==
nullptr) &&
1366 "top level parentScope must be a nullptr");
1370 auto *curNamesScope =
new (allocator.Allocate<UsedNamesScopeTy>())
1371 UsedNamesScopeTy(usedNames);
1373 numberValuesInRegion(*region);
1377 nameContext.push_back(std::make_tuple(®ion, nextValueID,
1378 nextArgumentID, nextConflictID,
1383 while (usedNames.getCurScope() !=
nullptr)
1384 usedNames.getCurScope()->~UsedNamesScopeTy();
1387 void SSANameState::printValueID(
Value value,
bool printResultNo,
1388 raw_ostream &stream)
const {
1390 stream <<
"<<NULL VALUE>>";
1394 std::optional<int> resultNo;
1395 auto lookupValue = value;
1399 if (
OpResult result = dyn_cast<OpResult>(value))
1400 getResultIDAndNumber(result, lookupValue, resultNo);
1402 auto it = valueIDs.find(lookupValue);
1403 if (it == valueIDs.end()) {
1404 stream <<
"<<UNKNOWN SSA VALUE>>";
1409 if (it->second != NameSentinel) {
1410 stream << it->second;
1412 auto nameIt = valueNames.find(lookupValue);
1413 assert(nameIt != valueNames.end() &&
"Didn't have a name entry?");
1414 stream << nameIt->second;
1417 if (resultNo && printResultNo)
1418 stream <<
'#' << *resultNo;
1421 void SSANameState::printOperationID(
Operation *op, raw_ostream &stream)
const {
1422 auto it = operationIDs.find(op);
1423 if (it == operationIDs.end()) {
1424 stream <<
"<<UNKNOWN OPERATION>>";
1426 stream <<
'%' << it->second;
1431 auto it = opResultGroups.find(op);
1432 return it == opResultGroups.end() ?
ArrayRef<int>() : it->second;
1435 BlockInfo SSANameState::getBlockInfo(
Block *block) {
1436 auto it = blockNames.find(block);
1437 BlockInfo invalidBlock{-1,
"INVALIDBLOCK"};
1438 return it != blockNames.end() ? it->second : invalidBlock;
1441 void SSANameState::shadowRegionArgs(
Region ®ion,
ValueRange namesToUse) {
1442 assert(!region.
empty() &&
"cannot shadow arguments of an empty region");
1444 "incorrect number of names passed in");
1446 "only KnownIsolatedFromAbove ops can shadow names");
1449 for (
unsigned i = 0, e = namesToUse.size(); i != e; ++i) {
1450 auto nameToUse = namesToUse[i];
1451 if (nameToUse ==
nullptr)
1456 llvm::raw_svector_ostream nameStream(nameStr);
1457 printValueID(nameToUse,
true, nameStream);
1460 assert(valueIDs[nameToReplace] == NameSentinel);
1463 auto name = StringRef(nameStream.str()).drop_front();
1466 valueNames[nameToReplace] = name.copy(usedNameAllocator);
1470 void SSANameState::numberValuesInRegion(
Region ®ion) {
1471 auto setBlockArgNameFn = [&](
Value arg, StringRef name) {
1472 assert(!valueIDs.count(arg) &&
"arg numbered multiple times");
1473 assert(llvm::cast<BlockArgument>(arg).getOwner()->getParent() == ®ion &&
1474 "arg not defined in current region");
1475 setValueName(arg, name);
1480 if (
auto asmInterface = dyn_cast<OpAsmOpInterface>(op))
1481 asmInterface.getAsmBlockArgumentNames(region, setBlockArgNameFn);
1486 unsigned nextBlockID = 0;
1487 for (
auto &block : region) {
1490 auto blockInfoIt = blockNames.insert({&block, {-1,
""}});
1491 if (blockInfoIt.second) {
1495 llvm::raw_string_ostream(name) <<
"^bb" << nextBlockID;
1496 blockInfoIt.first->second.name = StringRef(name).copy(usedNameAllocator);
1498 blockInfoIt.first->second.ordering = nextBlockID++;
1500 numberValuesInBlock(block);
1504 void SSANameState::numberValuesInBlock(
Block &block) {
1509 llvm::raw_svector_ostream specialName(specialNameBuffer);
1511 if (valueIDs.count(arg))
1514 specialNameBuffer.resize(strlen(
"arg"));
1515 specialName << nextArgumentID++;
1517 setValueName(arg, specialName.str());
1521 for (
auto &op : block)
1522 numberValuesInOp(op);
1525 void SSANameState::numberValuesInOp(
Operation &op) {
1528 auto setResultNameFn = [&](
Value result, StringRef name) {
1529 assert(!valueIDs.count(result) &&
"result numbered multiple times");
1530 assert(result.
getDefiningOp() == &op &&
"result not defined by 'op'");
1531 setValueName(result, name);
1534 if (
int resultNo = llvm::cast<OpResult>(result).getResultNumber())
1535 resultGroups.push_back(resultNo);
1538 auto setBlockNameFn = [&](
Block *block, StringRef name) {
1540 "getAsmBlockArgumentNames callback invoked on a block not directly "
1541 "nested under the current operation");
1542 assert(!blockNames.count(block) &&
"block numbered multiple times");
1545 if (name.data() != tmpBuffer.data()) {
1546 tmpBuffer.append(name);
1547 name = tmpBuffer.str();
1549 name = name.copy(usedNameAllocator);
1550 blockNames[block] = {-1, name};
1554 if (OpAsmOpInterface asmInterface = dyn_cast<OpAsmOpInterface>(&op)) {
1555 asmInterface.getAsmBlockNames(setBlockNameFn);
1556 asmInterface.getAsmResultNames(setResultNameFn);
1561 if (numResults == 0) {
1564 if (operationIDs.try_emplace(&op, nextValueID).second)
1572 if (valueIDs.try_emplace(resultBegin, nextValueID).second)
1576 if (resultGroups.size() != 1) {
1577 llvm::array_pod_sort(resultGroups.begin(), resultGroups.end());
1578 opResultGroups.try_emplace(&op, std::move(resultGroups));
1582 void SSANameState::getResultIDAndNumber(
1584 std::optional<int> &lookupResultNo)
const {
1592 auto resultGroupIt = opResultGroups.find(owner);
1593 if (resultGroupIt == opResultGroups.end()) {
1595 lookupResultNo = resultNo;
1602 const auto *it = llvm::upper_bound(resultGroups, resultNo);
1603 int groupResultNo = 0, groupSize = 0;
1606 if (it == resultGroups.end()) {
1607 groupResultNo = resultGroups.back();
1608 groupSize =
static_cast<int>(owner->
getNumResults()) - resultGroups.back();
1611 groupResultNo = *std::prev(it);
1612 groupSize = *it - groupResultNo;
1617 lookupResultNo = resultNo - groupResultNo;
1618 lookupValue = owner->
getResult(groupResultNo);
1621 void SSANameState::setValueName(
Value value, StringRef name) {
1624 valueIDs[value] = nextValueID++;
1628 valueIDs[value] = NameSentinel;
1629 valueNames[value] = uniqueValueName(name);
1632 StringRef SSANameState::uniqueValueName(StringRef name) {
1637 if (!usedNames.count(name)) {
1638 name = name.copy(usedNameAllocator);
1644 probeName.push_back(
'_');
1646 probeName += llvm::utostr(nextConflictID++);
1647 if (!usedNames.count(probeName)) {
1648 name = probeName.str().copy(usedNameAllocator);
1651 probeName.resize(name.size() + 1);
1655 usedNames.insert(name,
char());
1665 class DistinctState {
1671 uint64_t distinctCounter = 0;
1676 uint64_t DistinctState::getId(
DistinctAttr distinctAttr) {
1677 auto [it, inserted] =
1678 distinctAttrMap.try_emplace(distinctAttr, distinctCounter);
1681 return it->getSecond();
1688 AsmParsedResourceEntry::~AsmParsedResourceEntry() =
default;
1689 AsmResourceBuilder::~AsmResourceBuilder() =
default;
1690 AsmResourceParser::~AsmResourceParser() =
default;
1691 AsmResourcePrinter::~AsmResourcePrinter() =
default;
1695 case AsmResourceEntryKind::Blob:
1697 case AsmResourceEntryKind::Bool:
1699 case AsmResourceEntryKind::String:
1702 llvm_unreachable(
"unknown AsmResourceEntryKind");
1706 std::unique_ptr<ResourceCollection> &collection = keyToResources[key.str()];
1708 collection = std::make_unique<ResourceCollection>(key);
1712 std::vector<std::unique_ptr<AsmResourcePrinter>>
1714 std::vector<std::unique_ptr<AsmResourcePrinter>> printers;
1715 for (
auto &it : keyToResources) {
1716 ResourceCollection *collection = it.second.get();
1718 return collection->buildResources(op, builder);
1720 printers.emplace_back(
1726 LogicalResult FallbackAsmResourceMap::ResourceCollection::parseResource(
1733 resources.emplace_back(entry.
getKey(), std::move(*blob));
1740 resources.emplace_back(entry.
getKey(), *value);
1747 resources.emplace_back(entry.
getKey(), std::move(*str));
1754 void FallbackAsmResourceMap::ResourceCollection::buildResources(
1756 for (
const auto &entry : resources) {
1757 if (
const auto *value = std::get_if<AsmResourceBlob>(&entry.value))
1759 else if (
const auto *value = std::get_if<bool>(&entry.value))
1761 else if (
const auto *value = std::get_if<std::string>(&entry.value))
1764 llvm_unreachable(
"unknown AsmResourceEntryKind");
1778 : interfaces(op->
getContext()), nameState(op, printerFlags),
1779 printerFlags(printerFlags), locationMap(locationMap) {}
1782 : interfaces(ctx), printerFlags(printerFlags), locationMap(locationMap) {}
1786 aliasState.initialize(op, printerFlags, interfaces);
1806 return llvm::make_pointee_range(externalResourcePrinters);
1816 (*locationMap)[op] = std::make_pair(line, col);
1822 return dialectResources;
1826 return success(cyclicPrintingStack.insert(opaquePointer));
1842 AliasState aliasState;
1845 SSANameState nameState;
1848 DistinctState distinctState;
1873 return printerFlags;
1875 LLVM_DEBUG(llvm::dbgs() <<
DEBUG_TYPE <<
": Verifying operation: "
1880 auto parentThreadId = llvm::get_threadid();
1882 if (parentThreadId == llvm::get_threadid()) {
1884 diag.print(llvm::dbgs());
1885 llvm::dbgs() <<
"\n";
1892 LLVM_DEBUG(llvm::dbgs()
1894 <<
"' failed to verify and will be printed in generic form\n");
1898 return printerFlags;
1917 return impl->getPrinterFlags();
1921 std::unique_ptr<AsmResourcePrinter> printer) {
1922 impl->externalResourcePrinters.emplace_back(std::move(printer));
1927 return impl->getDialectResources();
1935 : os(os), state(state), printerFlags(state.getPrinterFlags()) {}
1943 printLocation(loc, allowAlias);
1949 if (!isTopLevel &&
succeeded(state.getAliasState().getAlias(loc, os)))
1953 .Case<OpaqueLoc>([&](OpaqueLoc loc) {
1954 printLocationInternal(loc.getFallbackLocation(), pretty);
1956 .Case<UnknownLoc>([&](UnknownLoc loc) {
1962 .Case<FileLineColLoc>([&](FileLineColLoc loc) {
1964 os << loc.getFilename().getValue();
1966 printEscapedString(loc.getFilename());
1967 os <<
':' << loc.getLine() <<
':' << loc.getColumn();
1969 .Case<NameLoc>([&](NameLoc loc) {
1970 printEscapedString(loc.getName());
1973 auto childLoc = loc.getChildLoc();
1974 if (!llvm::isa<UnknownLoc>(childLoc)) {
1976 printLocationInternal(childLoc, pretty);
1980 .Case<CallSiteLoc>([&](CallSiteLoc loc) {
1985 printLocationInternal(callee, pretty);
1987 if (llvm::isa<NameLoc>(callee)) {
1988 if (llvm::isa<FileLineColLoc>(caller)) {
1991 os << newLine <<
" at ";
1994 os << newLine <<
" at ";
1999 printLocationInternal(caller, pretty);
2003 .Case<FusedLoc>([&](
FusedLoc loc) {
2006 if (
Attribute metadata = loc.getMetadata()) {
2014 [&](Location loc) { printLocationInternal(loc, pretty); },
2015 [&]() { os << ", "; });
2022 static void printFloatValue(const APFloat &apValue, raw_ostream &os) {
2023 // We would like to output the FP constant value in exponential notation,
2024 // but we cannot do this if doing so will lose precision. Check here to
2025 // make sure that we only output it in exponential format if we can parse
2026 // the value back and get the same value.
2027 bool isInf = apValue.isInfinity();
2028 bool isNaN = apValue.isNaN();
2029 if (!isInf && !isNaN) {
2030 SmallString<128> strValue;
2031 apValue.toString(strValue, /*FormatPrecision=*/6, /*FormatMaxPadding=*/0,
2032 /*TruncateZero=*/false);
2034 // Check to make sure that the stringized number is not some string like
2035 // "Inf" or NaN, that atof will accept, but the lexer will not. Check
2036 // that the string matches the "[-+]?[0-9]" regex.
2037 assert(((strValue[0] >= '0
' && strValue[0] <= '9') ||
2038 ((strValue[0] ==
'-' || strValue[0] ==
'+') &&
2039 (strValue[1] >=
'0' && strValue[1] <=
'9'))) &&
2040 "[-+]?[0-9] regex does not match!");
2044 if (APFloat(apValue.getSemantics(), strValue).bitwiseIsEqual(apValue)) {
2052 apValue.toString(strValue);
2055 if (strValue.str().contains(
'.')) {
2064 APInt apInt = apValue.bitcastToAPInt();
2065 apInt.toString(str, 16,
false,
2072 return printLocationInternal(loc,
true,
true);
2075 if (!allowAlias ||
failed(printAlias(loc)))
2076 printLocationInternal(loc,
false,
true);
2084 state.getDialectResources()[resource.
getDialect()].insert(resource);
2092 if (symName.empty() || !isalpha(symName.front()))
2097 symName = symName.drop_while(
2098 [](
char c) {
return llvm::isAlnum(c) || c ==
'.' || c ==
'_'; });
2099 if (symName.empty())
2104 return symName.front() ==
'<' && symName.back() ==
'>';
2109 StringRef dialectName, StringRef symString) {
2110 os << symPrefix << dialectName;
2115 os <<
'.' << symString;
2119 os << '<' << symString << '>
';
2123 static bool isBareIdentifier(StringRef name) {
2124 // By making this unsigned, the value passed in to isalnum will always be
2125 // in the range 0-255. This is important when building with MSVC because
2126 // its implementation will assert. This situation can arise when dealing
2127 // with UTF-8 multibyte characters.
2128 if (name.empty() || (!isalpha(name[0]) && name[0] != '_
'))
2130 return llvm::all_of(name.drop_front(), [](unsigned char c) {
2131 return isalnum(c) || c == '_
' || c == '$
' || c == '.
';
2137 static void printKeywordOrString(StringRef keyword, raw_ostream &os) {
2138 // If it can be represented as a bare identifier, write it directly.
2139 if (isBareIdentifier(keyword)) {
2144 // Otherwise, output the keyword wrapped in quotes with proper escaping.
2146 printEscapedString(keyword, os);
2153 static void printSymbolReference(StringRef symbolRef, raw_ostream &os) {
2154 if (symbolRef.empty()) {
2155 os << "@<<INVALID EMPTY SYMBOL>>
";
2159 printKeywordOrString(symbolRef, os);
2162 // Print out a valid ElementsAttr that is succinct and can represent any
2163 // potential shape/type, for use when eliding a large ElementsAttr.
2165 // We choose to use a dense resource ElementsAttr literal with conspicuous
2166 // content to hopefully alert readers to the fact that this has been elided.
2167 static void printElidedElementsAttr(raw_ostream &os) {
2168 os << R"(dense_resource<__elided__>)
";
2171 LogicalResult AsmPrinter::Impl::printAlias(Attribute attr) {
2172 return state.getAliasState().getAlias(attr, os);
2175 LogicalResult AsmPrinter::Impl::printAlias(Type type) {
2176 return state.getAliasState().getAlias(type, os);
2179 void AsmPrinter::Impl::printAttribute(Attribute attr,
2180 AttrTypeElision typeElision) {
2182 os << "<<NULL ATTRIBUTE>>
";
2186 // Try to print an alias for this attribute.
2187 if (succeeded(printAlias(attr)))
2189 return printAttributeImpl(attr, typeElision);
2192 void AsmPrinter::Impl::printAttributeImpl(Attribute attr,
2193 AttrTypeElision typeElision) {
2194 if (!isa<BuiltinDialect>(attr.getDialect())) {
2195 printDialectAttribute(attr);
2196 } else if (auto opaqueAttr = llvm::dyn_cast<OpaqueAttr>(attr)) {
2197 printDialectSymbol(os, "#
", opaqueAttr.getDialectNamespace(),
2198 opaqueAttr.getAttrData());
2199 } else if (llvm::isa<UnitAttr>(attr)) {
2202 } else if (auto distinctAttr = llvm::dyn_cast<DistinctAttr>(attr)) {
2203 os << "distinct[
" << state.getDistinctState().getId(distinctAttr) << "]<
";
2204 if (!llvm::isa<UnitAttr>(distinctAttr.getReferencedAttr())) {
2205 printAttribute(distinctAttr.getReferencedAttr());
2209 } else if (auto dictAttr = llvm::dyn_cast<DictionaryAttr>(attr)) {
2211 interleaveComma(dictAttr.getValue(),
2212 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2215 } else if (auto intAttr = llvm::dyn_cast<IntegerAttr>(attr)) {
2216 Type intType = intAttr.getType();
2217 if (intType.isSignlessInteger(1)) {
2218 os << (intAttr.getValue().getBoolValue() ? "true" : "false");
2220 // Boolean integer attributes always elides the type.
2224 // Only print attributes as unsigned if they are explicitly unsigned or are
2225 // signless 1-bit values. Indexes, signed values, and multi-bit signless
2226 // values print as signed.
2228 intType.isUnsignedInteger() || intType.isSignlessInteger(1);
2229 intAttr.getValue().print(os, !isUnsigned);
2231 // IntegerAttr elides the type if I64.
2232 if (typeElision == AttrTypeElision::May && intType.isSignlessInteger(64))
2235 } else if (auto floatAttr = llvm::dyn_cast<FloatAttr>(attr)) {
2236 printFloatValue(floatAttr.getValue(), os);
2238 // FloatAttr elides the type if F64.
2239 if (typeElision == AttrTypeElision::May && floatAttr.getType().isF64())
2242 } else if (auto strAttr = llvm::dyn_cast<StringAttr>(attr)) {
2243 printEscapedString(strAttr.getValue());
2245 } else if (auto arrayAttr = llvm::dyn_cast<ArrayAttr>(attr)) {
2247 interleaveComma(arrayAttr.getValue(), [&](Attribute attr) {
2248 printAttribute(attr, AttrTypeElision::May);
2252 } else if (auto affineMapAttr = llvm::dyn_cast<AffineMapAttr>(attr)) {
2253 os << "affine_map<
";
2254 affineMapAttr.getValue().print(os);
2257 // AffineMap always elides the type.
2260 } else if (auto integerSetAttr = llvm::dyn_cast<IntegerSetAttr>(attr)) {
2261 os << "affine_set<
";
2262 integerSetAttr.getValue().print(os);
2265 // IntegerSet always elides the type.
2268 } else if (auto typeAttr = llvm::dyn_cast<TypeAttr>(attr)) {
2269 printType(typeAttr.getValue());
2271 } else if (auto refAttr = llvm::dyn_cast<SymbolRefAttr>(attr)) {
2272 printSymbolReference(refAttr.getRootReference().getValue(), os);
2273 for (FlatSymbolRefAttr nestedRef : refAttr.getNestedReferences()) {
2275 printSymbolReference(nestedRef.getValue(), os);
2278 } else if (auto intOrFpEltAttr =
2279 llvm::dyn_cast<DenseIntOrFPElementsAttr>(attr)) {
2280 if (printerFlags.shouldElideElementsAttr(intOrFpEltAttr)) {
2281 printElidedElementsAttr(os);
2284 printDenseIntOrFPElementsAttr(intOrFpEltAttr, /*allowHex=*/true);
2288 } else if (auto strEltAttr = llvm::dyn_cast<DenseStringElementsAttr>(attr)) {
2289 if (printerFlags.shouldElideElementsAttr(strEltAttr)) {
2290 printElidedElementsAttr(os);
2293 printDenseStringElementsAttr(strEltAttr);
2297 } else if (auto sparseEltAttr = llvm::dyn_cast<SparseElementsAttr>(attr)) {
2298 if (printerFlags.shouldElideElementsAttr(sparseEltAttr.getIndices()) ||
2299 printerFlags.shouldElideElementsAttr(sparseEltAttr.getValues())) {
2300 printElidedElementsAttr(os);
2303 DenseIntElementsAttr indices = sparseEltAttr.getIndices();
2304 if (indices.getNumElements() != 0) {
2305 printDenseIntOrFPElementsAttr(indices, /*allowHex=*/false);
2307 printDenseElementsAttr(sparseEltAttr.getValues(), /*allowHex=*/true);
2311 } else if (auto stridedLayoutAttr = llvm::dyn_cast<StridedLayoutAttr>(attr)) {
2312 stridedLayoutAttr.print(os);
2313 } else if (auto denseArrayAttr = llvm::dyn_cast<DenseArrayAttr>(attr)) {
2315 printType(denseArrayAttr.getElementType());
2316 if (!denseArrayAttr.empty()) {
2318 printDenseArrayAttr(denseArrayAttr);
2322 } else if (auto resourceAttr =
2323 llvm::dyn_cast<DenseResourceElementsAttr>(attr)) {
2324 os << "dense_resource<
";
2325 printResourceHandle(resourceAttr.getRawHandle());
2327 } else if (auto locAttr = llvm::dyn_cast<LocationAttr>(attr)) {
2328 printLocation(locAttr);
2330 llvm::report_fatal_error("Unknown builtin attribute
");
2332 // Don't print the type if we must elide it, or if it is a None type.
2333 if (typeElision != AttrTypeElision::Must) {
2334 if (auto typedAttr = llvm::dyn_cast<TypedAttr>(attr)) {
2335 Type attrType = typedAttr.getType();
2336 if (!llvm::isa<NoneType>(attrType)) {
2338 printType(attrType);
2345 static void printDenseIntElement(const APInt &value, raw_ostream &os,
2347 if (type.isInteger(1))
2348 os << (value.getBoolValue() ? "
true" : "false");
2350 value.print(os, !type.isUnsignedInteger());
2354 printDenseElementsAttrImpl(bool isSplat, ShapedType type, raw_ostream &os,
2355 function_ref<void(unsigned)> printEltFn) {
2356 // Special case for 0-d and splat tensors.
2358 return printEltFn(0);
2360 // Special case for degenerate tensors.
2361 auto numElements = type.getNumElements();
2362 if (numElements == 0)
2365 // We use a mixed-radix counter to iterate through the shape. When we bump a
2366 // non-least-significant digit, we emit a close bracket. When we next emit an
2367 // element we re-open all closed brackets.
2369 // The mixed-radix counter, with radices in 'shape'.
2370 int64_t rank = type.getRank();
2371 SmallVector<unsigned, 4> counter(rank, 0);
2372 // The number of brackets that have been opened and not closed.
2373 unsigned openBrackets = 0;
2375 auto shape = type.getShape();
2376 auto bumpCounter = [&] {
2377 // Bump the least significant digit.
2378 ++counter[rank - 1];
2379 // Iterate backwards bubbling back the increment.
2380 for (unsigned i = rank - 1; i > 0; --i)
2381 if (counter[i] >= shape[i]) {
2382 // Index 'i' is rolled over. Bump (i-1) and close a bracket.
2390 for (unsigned idx = 0, e = numElements; idx != e; ++idx) {
2393 while (openBrackets++ < rank)
2395 openBrackets = rank;
2399 while (openBrackets-- > 0)
2403 void AsmPrinter::Impl::printDenseElementsAttr(DenseElementsAttr attr,
2405 if (auto stringAttr = llvm::dyn_cast<DenseStringElementsAttr>(attr))
2406 return printDenseStringElementsAttr(stringAttr);
2408 printDenseIntOrFPElementsAttr(llvm::cast<DenseIntOrFPElementsAttr>(attr),
2412 void AsmPrinter::Impl::printDenseIntOrFPElementsAttr(
2413 DenseIntOrFPElementsAttr attr, bool allowHex) {
2414 auto type = attr.getType();
2415 auto elementType = type.getElementType();
2417 // Check to see if we should format this attribute as a hex string.
2418 auto numElements = type.getNumElements();
2419 if (!attr.isSplat() && allowHex &&
2420 shouldPrintElementsAttrWithHex(numElements)) {
2421 ArrayRef<char> rawData = attr.getRawData();
2422 if (llvm::endianness::native == llvm::endianness::big) {
2423 // Convert endianess in big-endian(BE) machines. `rawData` is BE in BE
2424 // machines. It is converted here to print in LE format.
2425 SmallVector<char, 64> outDataVec(rawData.size());
2426 MutableArrayRef<char> convRawData(outDataVec);
2427 DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
2428 rawData, convRawData, type);
2429 printHexString(convRawData);
2431 printHexString(rawData);
2437 if (ComplexType complexTy = llvm::dyn_cast<ComplexType>(elementType)) {
2438 Type complexElementType = complexTy.getElementType();
2439 // Note: The if and else below had a common lambda function which invoked
2440 // printDenseElementsAttrImpl. This lambda was hitting a bug in gcc 9.1,9.2
2441 // and hence was replaced.
2442 if (llvm::isa<IntegerType>(complexElementType)) {
2443 auto valueIt = attr.value_begin<std::complex<APInt>>();
2444 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2445 auto complexValue = *(valueIt + index);
2447 printDenseIntElement(complexValue.real(), os, complexElementType);
2449 printDenseIntElement(complexValue.imag(), os, complexElementType);
2453 auto valueIt = attr.value_begin<std::complex<APFloat>>();
2454 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2455 auto complexValue = *(valueIt + index);
2457 printFloatValue(complexValue.real(), os);
2459 printFloatValue(complexValue.imag(), os);
2463 } else if (elementType.isIntOrIndex()) {
2464 auto valueIt = attr.value_begin<APInt>();
2465 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2466 printDenseIntElement(*(valueIt + index), os, elementType);
2469 assert(llvm::isa<FloatType>(elementType) && "unexpected element type
");
2470 auto valueIt = attr.value_begin<APFloat>();
2471 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2472 printFloatValue(*(valueIt + index), os);
2477 void AsmPrinter::Impl::printDenseStringElementsAttr(
2478 DenseStringElementsAttr attr) {
2479 ArrayRef<StringRef> data = attr.getRawStringData();
2480 auto printFn = [&](unsigned index) { printEscapedString(data[index]); };
2481 printDenseElementsAttrImpl(attr.isSplat(), attr.getType(), os, printFn);
2484 void AsmPrinter::Impl::printDenseArrayAttr(DenseArrayAttr attr) {
2485 Type type = attr.getElementType();
2486 unsigned bitwidth = type.isInteger(1) ? 8 : type.getIntOrFloatBitWidth();
2487 unsigned byteSize = bitwidth / 8;
2488 ArrayRef<char> data = attr.getRawData();
2490 auto printElementAt = [&](unsigned i) {
2491 APInt value(bitwidth, 0);
2493 llvm::LoadIntFromMemory(
2494 value, reinterpret_cast<const uint8_t *>(data.begin() + byteSize * i),
2497 // Print the data as-is or as a float.
2498 if (type.isIntOrIndex()) {
2499 printDenseIntElement(value, getStream(), type);
2501 APFloat fltVal(llvm::cast<FloatType>(type).getFloatSemantics(), value);
2502 printFloatValue(fltVal, getStream());
2505 llvm::interleaveComma(llvm::seq<unsigned>(0, attr.size()), getStream(),
2509 void AsmPrinter::Impl::printType(Type type) {
2511 os << "<<NULL TYPE>>
";
2515 // Try to print an alias for this type.
2516 if (succeeded(printAlias(type)))
2518 return printTypeImpl(type);
2521 void AsmPrinter::Impl::printTypeImpl(Type type) {
2522 TypeSwitch<Type>(type)
2523 .Case<OpaqueType>([&](OpaqueType opaqueTy) {
2524 printDialectSymbol(os, "!
", opaqueTy.getDialectNamespace(),
2525 opaqueTy.getTypeData());
2527 .Case<IndexType>([&](Type) { os << "index
"; })
2528 .Case<Float8E5M2Type>([&](Type) { os << "f8E5M2
"; })
2529 .Case<Float8E4M3FNType>([&](Type) { os << "f8E4M3FN
"; })
2530 .Case<Float8E5M2FNUZType>([&](Type) { os << "f8E5M2FNUZ
"; })
2531 .Case<Float8E4M3FNUZType>([&](Type) { os << "f8E4M3FNUZ
"; })
2532 .Case<Float8E4M3B11FNUZType>([&](Type) { os << "f8E4M3B11FNUZ
"; })
2533 .Case<BFloat16Type>([&](Type) { os << "bf16"; })
2534 .Case<Float16Type>([&](Type) { os << "f16"; })
2535 .Case<FloatTF32Type>([&](Type) { os << "tf32
"; })
2536 .Case<Float32Type>([&](Type) { os << "f32
"; })
2537 .Case<Float64Type>([&](Type) { os << "f64
"; })
2538 .Case<Float80Type>([&](Type) { os << "f80
"; })
2539 .Case<Float128Type>([&](Type) { os << "f128
"; })
2540 .Case<IntegerType>([&](IntegerType integerTy) {
2541 if (integerTy.isSigned())
2543 else if (integerTy.isUnsigned())
2545 os << 'i' << integerTy.getWidth();
2547 .Case<FunctionType>([&](FunctionType funcTy) {
2549 interleaveComma(funcTy.getInputs(), [&](Type ty) { printType(ty); });
2551 ArrayRef<Type> results = funcTy.getResults();
2552 if (results.size() == 1 && !llvm::isa<FunctionType>(results[0])) {
2553 printType(results[0]);
2556 interleaveComma(results, [&](Type ty) { printType(ty); });
2560 .Case<VectorType>([&](VectorType vectorTy) {
2561 auto scalableDims = vectorTy.getScalableDims();
2563 auto vShape = vectorTy.getShape();
2564 unsigned lastDim = vShape.size();
2565 unsigned dimIdx = 0;
2566 for (dimIdx = 0; dimIdx < lastDim; dimIdx++) {
2567 if (!scalableDims.empty() && scalableDims[dimIdx])
2569 os << vShape[dimIdx];
2570 if (!scalableDims.empty() && scalableDims[dimIdx])
2574 printType(vectorTy.getElementType());
2577 .Case<RankedTensorType>([&](RankedTensorType tensorTy) {
2579 for (int64_t dim : tensorTy.getShape()) {
2580 if (ShapedType::isDynamic(dim))
2586 printType(tensorTy.getElementType());
2587 // Only print the encoding attribute value if set.
2588 if (tensorTy.getEncoding()) {
2590 printAttribute(tensorTy.getEncoding());
2594 .Case<UnrankedTensorType>([&](UnrankedTensorType tensorTy) {
2596 printType(tensorTy.getElementType());
2599 .Case<MemRefType>([&](MemRefType memrefTy) {
2601 for (int64_t dim : memrefTy.getShape()) {
2602 if (ShapedType::isDynamic(dim))
2608 printType(memrefTy.getElementType());
2609 MemRefLayoutAttrInterface layout = memrefTy.getLayout();
2610 if (!llvm::isa<AffineMapAttr>(layout) || !layout.isIdentity()) {
2612 printAttribute(memrefTy.getLayout(), AttrTypeElision::May);
2614 // Only print the memory space if it is the non-default one.
2615 if (memrefTy.getMemorySpace()) {
2617 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2621 .Case<UnrankedMemRefType>([&](UnrankedMemRefType memrefTy) {
2623 printType(memrefTy.getElementType());
2624 // Only print the memory space if it is the non-default one.
2625 if (memrefTy.getMemorySpace()) {
2627 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2631 .Case<ComplexType>([&](ComplexType complexTy) {
2633 printType(complexTy.getElementType());
2636 .Case<TupleType>([&](TupleType tupleTy) {
2638 interleaveComma(tupleTy.getTypes(),
2639 [&](Type type) { printType(type); });
2642 .Case<NoneType>([&](Type) { os << "none
"; })
2643 .Default([&](Type type) { return printDialectType(type); });
2646 void AsmPrinter::Impl::printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
2647 ArrayRef<StringRef> elidedAttrs,
2649 // If there are no attributes, then there is nothing to be done.
2653 // Functor used to print a filtered attribute list.
2654 auto printFilteredAttributesFn = [&](auto filteredAttrs) {
2655 // Print the 'attributes' keyword if necessary.
2657 os << " attributes
";
2659 // Otherwise, print them all out in braces.
2661 interleaveComma(filteredAttrs,
2662 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2666 // If no attributes are elided, we can directly print with no filtering.
2667 if (elidedAttrs.empty())
2668 return printFilteredAttributesFn(attrs);
2670 // Otherwise, filter out any attributes that shouldn't be included.
2671 llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
2673 auto filteredAttrs = llvm::make_filter_range(attrs, [&](NamedAttribute attr) {
2674 return !elidedAttrsSet.contains(attr.getName().strref());
2676 if (!filteredAttrs.empty())
2677 printFilteredAttributesFn(filteredAttrs);
2679 void AsmPrinter::Impl::printNamedAttribute(NamedAttribute attr) {
2680 // Print the name without quotes if possible.
2681 ::printKeywordOrString(attr.getName().strref(), os);
2683 // Pretty printing elides the attribute value for unit attributes.
2684 if (llvm::isa<UnitAttr>(attr.getValue()))
2688 printAttribute(attr.getValue());
2691 void AsmPrinter::Impl::printDialectAttribute(Attribute attr) {
2692 auto &dialect = attr.getDialect();
2694 // Ask the dialect to serialize the attribute to a string.
2695 std::string attrName;
2697 llvm::raw_string_ostream attrNameStr(attrName);
2698 Impl subPrinter(attrNameStr, state);
2699 DialectAsmPrinter printer(subPrinter);
2700 dialect.printAttribute(attr, printer);
2702 printDialectSymbol(os, "#
", dialect.getNamespace(), attrName);
2705 void AsmPrinter::Impl::printDialectType(Type type) {
2706 auto &dialect = type.getDialect();
2708 // Ask the dialect to serialize the type to a string.
2709 std::string typeName;
2711 llvm::raw_string_ostream typeNameStr(typeName);
2712 Impl subPrinter(typeNameStr, state);
2713 DialectAsmPrinter printer(subPrinter);
2714 dialect.printType(type, printer);
2716 printDialectSymbol(os, "!
", dialect.getNamespace(), typeName);
2719 void AsmPrinter::Impl::printEscapedString(StringRef str) {
2721 llvm::printEscapedString(str, os);
2726 os <<
"\"0x" << llvm::toHex(str) <<
"\"";
2729 printHexString(StringRef(data.data(), data.size()));
2733 return state.pushCyclicPrinting(opaquePointer);
2745 assert(
impl &&
"expected AsmPrinter::getStream to be overriden");
2746 return impl->getStream();
2751 assert(
impl &&
"expected AsmPrinter::printFloat to be overriden");
2756 assert(
impl &&
"expected AsmPrinter::printType to be overriden");
2757 impl->printType(type);
2761 assert(
impl &&
"expected AsmPrinter::printAttribute to be overriden");
2762 impl->printAttribute(attr);
2766 assert(
impl &&
"expected AsmPrinter::printAlias to be overriden");
2767 return impl->printAlias(attr);
2771 assert(
impl &&
"expected AsmPrinter::printAlias to be overriden");
2772 return impl->printAlias(type);
2777 "expected AsmPrinter::printAttributeWithoutType to be overriden");
2782 assert(
impl &&
"expected AsmPrinter::printKeywordOrString to be overriden");
2787 assert(
impl &&
"expected AsmPrinter::printString to be overriden");
2789 printEscapedString(keyword,
getStream());
2794 assert(
impl &&
"expected AsmPrinter::printSymbolName to be overriden");
2799 assert(
impl &&
"expected AsmPrinter::printResourceHandle to be overriden");
2800 impl->printResourceHandle(resource);
2804 return impl->pushCyclicPrinting(opaquePointer);
2815 printAffineExprInternal(expr, BindingStrength::Weak, printValueName);
2821 const char *binopSpelling =
nullptr;
2824 unsigned pos = cast<AffineSymbolExpr>(expr).getPosition();
2826 printValueName(pos,
true);
2832 unsigned pos = cast<AffineDimExpr>(expr).getPosition();
2834 printValueName(pos,
false);
2840 os << cast<AffineConstantExpr>(expr).getValue();
2843 binopSpelling =
" + ";
2846 binopSpelling =
" * ";
2849 binopSpelling =
" floordiv ";
2852 binopSpelling =
" ceildiv ";
2855 binopSpelling =
" mod ";
2859 auto binOp = cast<AffineBinaryOpExpr>(expr);
2865 if (enclosingTightness == BindingStrength::Strong)
2869 auto rhsConst = dyn_cast<AffineConstantExpr>(rhsExpr);
2871 rhsConst.getValue() == -1) {
2873 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
2874 if (enclosingTightness == BindingStrength::Strong)
2879 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
2881 os << binopSpelling;
2882 printAffineExprInternal(rhsExpr, BindingStrength::Strong, printValueName);
2884 if (enclosingTightness == BindingStrength::Strong)
2890 if (enclosingTightness == BindingStrength::Strong)
2895 if (
auto rhs = dyn_cast<AffineBinaryOpExpr>(rhsExpr)) {
2898 if (
auto rrhs = dyn_cast<AffineConstantExpr>(rrhsExpr)) {
2899 if (rrhs.getValue() == -1) {
2900 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
2904 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
2907 printAffineExprInternal(rhs.getLHS(), BindingStrength::Weak,
2911 if (enclosingTightness == BindingStrength::Strong)
2916 if (rrhs.getValue() < -1) {
2917 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
2920 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
2922 os <<
" * " << -rrhs.getValue();
2923 if (enclosingTightness == BindingStrength::Strong)
2932 if (
auto rhsConst = dyn_cast<AffineConstantExpr>(rhsExpr)) {
2933 if (rhsConst.getValue() < 0) {
2934 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
2935 os <<
" - " << -rhsConst.getValue();
2936 if (enclosingTightness == BindingStrength::Strong)
2942 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
2945 printAffineExprInternal(rhsExpr, BindingStrength::Weak, printValueName);
2947 if (enclosingTightness == BindingStrength::Strong)
2952 printAffineExprInternal(expr, BindingStrength::Weak);
2953 isEq ? os <<
" == 0" : os <<
" >= 0";
2959 for (
int i = 0; i < (int)map.
getNumDims() - 1; ++i)
2960 os <<
'd' << i <<
", ";
2969 os <<
's' << i <<
", ";
2978 [&](
AffineExpr expr) { printAffineExpr(expr); });
2985 for (
unsigned i = 1; i < set.
getNumDims(); ++i)
2986 os <<
'd' << i - 1 <<
", ";
2995 os <<
's' << i <<
", ";
3004 for (
int i = 1; i < numConstraints; ++i) {
3008 if (numConstraints >= 1)
3009 printAffineConstraint(set.
getConstraint(numConstraints - 1),
3010 set.
isEq(numConstraints - 1));
3025 explicit OperationPrinter(raw_ostream &os,
AsmStateImpl &state)
3029 void printTopLevelOperation(
Operation *op);
3033 void printFullOpWithIndentAndLoc(
Operation *op);
3039 void printCustomOrGenericOp(
Operation *op)
override;
3041 void printGenericOp(
Operation *op,
bool printOpName)
override;
3044 void printBlockName(
Block *block);
3049 void print(
Block *block,
bool printBlockArgs =
true,
3050 bool printBlockTerminator =
true);
3053 void printValueID(
Value value,
bool printResultNo =
true,
3054 raw_ostream *streamOverride =
nullptr)
const;
3058 raw_ostream *streamOverride =
nullptr)
const;
3066 void printOptionalLocationSpecifier(
Location loc)
override {
3067 printTrailingLocation(loc);
3074 os.indent(currentIndent);
3078 void increaseIndent()
override { currentIndent += indentWidth; }
3081 void decreaseIndent()
override { currentIndent -= indentWidth; }
3090 bool omitType =
false)
override;
3093 void printOperand(
Value value)
override { printValueID(value); }
3094 void printOperand(
Value value, raw_ostream &os)
override {
3095 printValueID(value,
true, &os);
3103 void printOptionalAttrDictWithKeyword(
3111 void printSuccessor(
Block *successor)
override;
3115 void printSuccessorAndUseList(
Block *successor,
3120 bool printBlockTerminators,
bool printEmptyBlock)
override;
3127 state.getSSANameState().shadowRegionArgs(region, namesToUse);
3132 void printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3147 void printValueUsers(
Value value);
3151 void printUserIDs(
Operation *user,
bool prefixComma =
false);
3159 using PrintFn =
function_ref<void(StringRef, ValueFn)>;
3161 ResourceBuilder(PrintFn printFn) : printFn(printFn) {}
3162 ~ResourceBuilder()
override =
default;
3164 void buildBool(StringRef key,
bool data)
final {
3165 printFn(key, [&](raw_ostream &os) { os << (data ?
"true" :
"false"); });
3168 void buildString(StringRef key, StringRef data)
final {
3169 printFn(key, [&](raw_ostream &os) {
3171 llvm::printEscapedString(data, os);
3177 uint32_t dataAlignment)
final {
3178 printFn(key, [&](raw_ostream &os) {
3180 llvm::support::ulittle32_t dataAlignmentLE(dataAlignment);
3182 << llvm::toHex(StringRef(
reinterpret_cast<char *
>(&dataAlignmentLE),
3183 sizeof(dataAlignment)))
3184 << llvm::toHex(StringRef(data.data(), data.size())) <<
"\"";
3193 void printFileMetadataDictionary(
Operation *op);
3199 void printResourceFileMetadata(
function_ref<
void()> checkAddMetadataDict,
3210 const static unsigned indentWidth = 2;
3213 unsigned currentIndent = 0;
3217 void OperationPrinter::printTopLevelOperation(
Operation *op) {
3219 state.getAliasState().printNonDeferredAliases(*
this, newLine);
3222 printFullOpWithIndentAndLoc(op);
3226 state.getAliasState().printDeferredAliases(*
this, newLine);
3229 printFileMetadataDictionary(op);
3232 void OperationPrinter::printFileMetadataDictionary(
Operation *op) {
3233 bool sawMetadataEntry =
false;
3234 auto checkAddMetadataDict = [&] {
3235 if (!std::exchange(sawMetadataEntry,
true))
3236 os << newLine <<
"{-#" << newLine;
3240 printResourceFileMetadata(checkAddMetadataDict, op);
3243 if (sawMetadataEntry)
3244 os << newLine <<
"#-}" << newLine;
3247 void OperationPrinter::printResourceFileMetadata(
3250 bool hadResource =
false;
3251 bool needResourceComma =
false;
3252 bool needEntryComma =
false;
3253 auto processProvider = [&](StringRef dictName, StringRef name,
auto &provider,
3254 auto &&...providerArgs) {
3255 bool hadEntry =
false;
3256 auto printFn = [&](StringRef key, ResourceBuilder::ValueFn valueFn) {
3257 checkAddMetadataDict();
3259 auto printFormatting = [&]() {
3261 if (!std::exchange(hadResource,
true)) {
3262 if (needResourceComma)
3263 os <<
"," << newLine;
3264 os <<
" " << dictName <<
"_resources: {" << newLine;
3267 if (!std::exchange(hadEntry,
true)) {
3269 os <<
"," << newLine;
3270 os <<
" " << name <<
": {" << newLine;
3272 os <<
"," << newLine;
3276 std::optional<uint64_t> charLimit =
3278 if (charLimit.has_value()) {
3279 std::string resourceStr;
3280 llvm::raw_string_ostream ss(resourceStr);
3284 if (resourceStr.size() > charLimit.value())
3288 os <<
" " << key <<
": " << resourceStr;
3291 os <<
" " << key <<
": ";
3295 ResourceBuilder entryBuilder(printFn);
3296 provider.buildResources(op, providerArgs..., entryBuilder);
3298 needEntryComma |= hadEntry;
3300 os << newLine <<
" }";
3306 auto &dialectResources = state.getDialectResources();
3307 StringRef name = interface.getDialect()->getNamespace();
3308 auto it = dialectResources.find(interface.getDialect());
3309 if (it != dialectResources.end())
3310 processProvider(
"dialect", name, interface, it->second);
3312 processProvider(
"dialect", name, interface,
3316 os << newLine <<
" }";
3320 needEntryComma =
false;
3321 needResourceComma = hadResource;
3322 hadResource =
false;
3323 for (
const auto &printer : state.getResourcePrinters())
3324 processProvider(
"external", printer.getName(), printer);
3326 os << newLine <<
" }";
3334 void OperationPrinter::printRegionArgument(
BlockArgument arg,
3342 printOptionalAttrDict(argAttrs);
3344 printTrailingLocation(arg.
getLoc(),
false);
3347 void OperationPrinter::printFullOpWithIndentAndLoc(
Operation *op) {
3349 state.registerOperationLocation(op, newLine.curLine, currentIndent);
3351 os.indent(currentIndent);
3353 printTrailingLocation(op->
getLoc());
3355 printUsersComment(op);
3358 void OperationPrinter::printFullOp(
Operation *op) {
3360 auto printResultGroup = [&](
size_t resultNo,
size_t resultCount) {
3361 printValueID(op->
getResult(resultNo),
false);
3362 if (resultCount > 1)
3363 os <<
':' << resultCount;
3367 ArrayRef<int> resultGroups = state.getSSANameState().getOpResultGroups(op);
3368 if (!resultGroups.empty()) {
3371 interleaveComma(llvm::seq<int>(0, resultGroups.size() - 1), [&](
int i) {
3372 printResultGroup(resultGroups[i],
3373 resultGroups[i + 1] - resultGroups[i]);
3376 printResultGroup(resultGroups.back(), numResults - resultGroups.back());
3379 printResultGroup(0, numResults);
3385 printCustomOrGenericOp(op);
3388 void OperationPrinter::printUsersComment(
Operation *op) {
3392 printOperationID(op);
3393 }
else if (numResults && op->
use_empty()) {
3395 }
else if (numResults && !op->
use_empty()) {
3398 unsigned usedInNResults = 0;
3399 unsigned usedInNOperations = 0;
3402 if (userSet.insert(user).second) {
3403 ++usedInNOperations;
3404 usedInNResults += user->getNumResults();
3409 bool exactlyOneUniqueUse =
3410 usedInNResults <= 1 && usedInNOperations <= 1 && numResults == 1;
3411 os <<
" // " << (exactlyOneUniqueUse ?
"user" :
"users") <<
": ";
3412 bool shouldPrintBrackets = numResults > 1;
3413 auto printOpResult = [&](
OpResult opResult) {
3414 if (shouldPrintBrackets)
3416 printValueUsers(opResult);
3417 if (shouldPrintBrackets)
3421 interleaveComma(op->
getResults(), printOpResult);
3425 void OperationPrinter::printUsersComment(
BlockArgument arg) {
3431 os <<
" is used by ";
3432 printValueUsers(arg);
3437 void OperationPrinter::printValueUsers(
Value value) {
3445 if (userSet.insert(user).second)
3446 printUserIDs(user, index);
3450 void OperationPrinter::printUserIDs(
Operation *user,
bool prefixComma) {
3455 printOperationID(user);
3458 [
this](
Value result) { printValueID(result); });
3462 void OperationPrinter::printCustomOrGenericOp(
Operation *op) {
3468 opInfo->printAssembly(op, *
this, defaultDialectStack.back());
3473 if (
auto opPrinter = dialect->getOperationPrinter(op)) {
3478 if (name.count(
'.') == 1)
3479 name.consume_front((defaultDialectStack.back() +
".").str());
3483 opPrinter(op, *
this);
3490 printGenericOp(op,
true);
3493 void OperationPrinter::printGenericOp(
Operation *op,
bool printOpName) {
3497 interleaveComma(op->
getOperands(), [&](
Value value) { printValueID(value); });
3504 [&](
Block *successor) { printBlockName(successor); });
3516 if (op->getNumRegions() != 0) {
3518 interleaveComma(op->getRegions(), [&](Region ®ion) {
3519 printRegion(region, /*printEntryBlockArgs=*/true,
3520 /*printBlockTerminators=*/true, /*printEmptyBlock=*/true);
3525 auto attrs = op->getDiscardableAttrs();
3526 printOptionalAttrDict(attrs);
3528 // Print the type signature of the operation.
3530 printFunctionalType(op);
3533 void OperationPrinter::printBlockName(Block *block) {
3534 os << state.getSSANameState().getBlockInfo(block).name;
3537 void OperationPrinter::print(Block *block, bool printBlockArgs,
3538 bool printBlockTerminator) {
3539 // Print the block label and argument list if requested.
3540 if (printBlockArgs) {
3541 os.indent(currentIndent);
3542 printBlockName(block);
3544 // Print the argument list if non-empty.
3545 if (!block->args_empty()) {
3547 interleaveComma(block->getArguments(), [&](BlockArgument arg) {
3550 printType(arg.getType());
3551 // TODO: We should allow location aliases on block arguments.
3552 printTrailingLocation(arg.getLoc(), /*allowAlias*/ false);
3558 // Print out some context information about the predecessors of this block.
3559 if (!block->getParent()) {
3560 os << " // block is not in a region!";
3561 } else if (block->hasNoPredecessors()) {
3562 if (!block->isEntryBlock())
3563 os << " // no predecessors";
3564 } else if (auto *pred = block->getSinglePredecessor()) {
3566 printBlockName(pred);
3568 // We want to print the predecessors in a stable order, not in
3569 // whatever order the use-list is in, so gather and sort them.
3570 SmallVector<BlockInfo, 4> predIDs;
3571 for (auto *pred : block->getPredecessors())
3572 predIDs.push_back(state.getSSANameState().getBlockInfo(pred));
3573 llvm::sort(predIDs, [](BlockInfo lhs, BlockInfo rhs) {
3574 return lhs.ordering < rhs.ordering;
3577 os << " // " << predIDs.size() << " preds: ";
3579 interleaveComma(predIDs, [&](BlockInfo pred) { os << pred.name; });
3584 currentIndent += indentWidth;
3586 if (printerFlags.shouldPrintValueUsers()) {
3587 for (BlockArgument arg : block->getArguments()) {
3588 os.indent(currentIndent);
3589 printUsersComment(arg);
3593 bool hasTerminator =
3594 !block->empty() && block->back().hasTrait<OpTrait::IsTerminator>();
3595 auto range = llvm::make_range(
3597 std::prev(block->end(),
3598 (!hasTerminator || printBlockTerminator) ? 0 : 1));
3599 for (auto &op : range) {
3600 printFullOpWithIndentAndLoc(&op);
3603 currentIndent -= indentWidth;
3606 void OperationPrinter::printValueID(Value value, bool printResultNo,
3607 raw_ostream *streamOverride) const {
3608 state.getSSANameState().printValueID(value, printResultNo,
3609 streamOverride ? *streamOverride : os);
3612 void OperationPrinter::printOperationID(Operation *op,
3613 raw_ostream *streamOverride) const {
3614 state.getSSANameState().printOperationID(op, streamOverride ? *streamOverride
3618 void OperationPrinter::printSuccessor(Block *successor) {
3619 printBlockName(successor);
3622 void OperationPrinter::printSuccessorAndUseList(Block *successor,
3623 ValueRange succOperands) {
3624 printBlockName(successor);
3625 if (succOperands.empty())
3629 interleaveComma(succOperands,
3630 [this](Value operand) { printValueID(operand); });
3632 interleaveComma(succOperands,
3633 [this](Value operand) { printType(operand.getType()); });
3637 void OperationPrinter::printRegion(Region ®ion, bool printEntryBlockArgs,
3638 bool printBlockTerminators,
3639 bool printEmptyBlock) {
3640 if (printerFlags.shouldSkipRegions()) {
3644 os << "{" << newLine;
3645 if (!region.empty()) {
3646 auto restoreDefaultDialect =
3647 llvm::make_scope_exit([&]() { defaultDialectStack.pop_back(); });
3648 if (auto iface = dyn_cast<OpAsmOpInterface>(region.getParentOp()))
3649 defaultDialectStack.push_back(iface.getDefaultDialect());
3651 defaultDialectStack.push_back("");
3653 auto *entryBlock = ®ion.front();
3654 // Force printing the block header if printEmptyBlock is set and the block
3655 // is empty or if printEntryBlockArgs is set and there are arguments to
3657 bool shouldAlwaysPrintBlockHeader =
3658 (printEmptyBlock && entryBlock->empty()) ||
3659 (printEntryBlockArgs && entryBlock->getNumArguments() != 0);
3660 print(entryBlock, shouldAlwaysPrintBlockHeader, printBlockTerminators);
3661 for (auto &b : llvm::drop_begin(region.getBlocks(), 1))
3664 os.indent(currentIndent) << "}";
3667 void OperationPrinter::printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3668 ValueRange operands) {
3670 os << "<<NULL AFFINE MAP>>";
3673 AffineMap map = mapAttr.getValue();
3674 unsigned numDims = map.getNumDims();
3675 auto printValueName = [&](unsigned pos, bool isSymbol) {
3676 unsigned index = isSymbol ? numDims + pos : pos;
3677 assert(index < operands.size());
3680 printValueID(operands[index]);
3685 interleaveComma(map.getResults(), [&](AffineExpr expr) {
3686 printAffineExpr(expr, printValueName);
3690 void OperationPrinter::printAffineExprOfSSAIds(AffineExpr expr,
3691 ValueRange dimOperands,
3692 ValueRange symOperands) {
3693 auto printValueName = [&](unsigned pos, bool isSymbol) {
3695 return printValueID(dimOperands[pos]);
3697 printValueID(symOperands[pos]);
3700 printAffineExpr(expr, printValueName);
3703 //===----------------------------------------------------------------------===//
3704 // print and dump methods
3705 //===----------------------------------------------------------------------===//
3707 void Attribute::print(raw_ostream &os, bool elideType) const {
3709 os << "<<NULL ATTRIBUTE>>";
3713 AsmState state(getContext());
3714 print(os, state, elideType);
3716 void Attribute::print(raw_ostream &os, AsmState &state, bool elideType) const {
3717 using AttrTypeElision = AsmPrinter::Impl::AttrTypeElision;
3718 AsmPrinter::Impl(os, state.getImpl())
3719 .printAttribute(*this, elideType ? AttrTypeElision::Must
3720 : AttrTypeElision::Never);
3723 void Attribute::dump() const {
3724 print(llvm::errs());
3725 llvm::errs() << "\n";
3728 void Type::print(raw_ostream &os) const {
3730 os << "<<NULL TYPE>>";
3734 AsmState state(getContext());
3737 void Type::print(raw_ostream &os, AsmState &state) const {
3738 AsmPrinter::Impl(os, state.getImpl()).printType(*this);
3741 void Type::dump() const {
3742 print(llvm::errs());
3743 llvm::errs() << "\n";
3746 void AffineMap::dump() const {
3747 print(llvm::errs());
3748 llvm::errs() << "\n";
3751 void IntegerSet::dump() const {
3752 print(llvm::errs());
3753 llvm::errs() << "\n";
3756 void AffineExpr::print(raw_ostream &os) const {
3758 os << "<<NULL AFFINE EXPR>>";
3761 AsmState state(getContext());
3762 AsmPrinter::Impl(os, state.getImpl()).printAffineExpr(*this);
3765 void AffineExpr::dump() const {
3766 print(llvm::errs());
3767 llvm::errs() << "\n";
3770 void AffineMap::print(raw_ostream &os) const {
3772 os << "<<NULL AFFINE MAP>>";
3775 AsmState state(getContext());
3776 AsmPrinter::Impl(os, state.getImpl()).printAffineMap(*this);
3779 void IntegerSet::print(raw_ostream &os) const {
3780 AsmState state(getContext());
3781 AsmPrinter::Impl(os, state.getImpl()).printIntegerSet(*this);
3784 void Value::print(raw_ostream &os) const { print(os, OpPrintingFlags()); }
3785 void Value::print(raw_ostream &os, const OpPrintingFlags &flags) const {
3787 os << "<<NULL VALUE>>";
3791 if (auto *op = getDefiningOp())
3792 return op->print(os, flags);
3793 // TODO: Improve BlockArgument print'ing.
3795 os <<
"<block argument> of type '" << arg.
getType()
3800 os <<
"<<NULL VALUE>>";
3804 if (
auto *op = getDefiningOp())
3805 return op->
print(os, state);
3809 os <<
"<block argument> of type '" << arg.
getType()
3814 print(llvm::errs());
3815 llvm::errs() <<
"\n";
3823 state.getImpl().getSSANameState().printValueID(*
this,
true,
3846 if (
auto result = llvm::dyn_cast<OpResult>(*
this)) {
3849 op = llvm::cast<BlockArgument>(*this).getOwner()->
getParentOp();
3851 os <<
"<<UNKNOWN SSA VALUE>>";
3857 printAsOperand(os, state);
3867 OperationPrinter printer(os, state.getImpl());
3868 if (!getParent() && !state.getPrinterFlags().shouldUseLocalScope()) {
3869 state.getImpl().initializeAliases(
this);
3870 printer.printTopLevelOperation(
this);
3872 printer.printFullOpWithIndentAndLoc(
this);
3878 llvm::errs() <<
"\n";
3884 os <<
"<<UNLINKED BLOCK>>\n";
3895 OperationPrinter(os, state.getImpl()).print(
this);
3904 os <<
"<<UNLINKED BLOCK>>\n";
3908 printAsOperand(os, state);
3911 OperationPrinter printer(os, state.getImpl());
3912 printer.printBlockName(
this);
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 bool shouldPrintElementsAttrWithHex(int64_t numElements)
Returns true if an ElementsAttr with the given number of elements should be printed with hex.
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.
static void printFloatValue(const APFloat &apValue, raw_ostream &os)
Print a floating point value in a way that the parser will be able to round-trip losslessly.
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
ParseResult parseTypeList(SmallVectorImpl< Type > &result)
Parse a type list.
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.
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 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)
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.
This class provides support for representing a failure result, or a valid value of type T.
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.
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.
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 shouldPrintValueUsers() const
Return if the printer should print users of values.
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 represents success/failure for parsing-like operations that find it important to chain tog...
This class contains a list of basic blocks and a link to the parent operation it is attached to.
iterator_range< OpIterator > getOps()
Operation * getParentOp()
Return the parent operation this region is attached to.
unsigned getNumArguments()
BlockArgument getArgument(unsigned i)
This diagnostic handler is a simple RAII class that registers and erases a diagnostic handler on a gi...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
const void * getAsOpaquePointer() const
Methods for supporting PointerLikeTypeTraits.
Dialect & getDialect() const
Get the dialect this type is registered to.
static Type getFromOpaquePointer(const void *pointer)
bool hasTrait()
Returns true if the type was registered with a particular trait.
void walkImmediateSubElements(function_ref< void(Attribute)> walkAttrsFn, function_ref< void(Type)> walkTypesFn) const
Walk all of the immediately nested sub-attributes and sub-types.
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
bool use_empty() const
Returns true if this value has no uses.
void print(raw_ostream &os) const
Type getType() const
Return the type of this value.
void printAsOperand(raw_ostream &os, AsmState &state) const
Print this value as if it were an operand.
user_range getUsers() const
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
void registerOperationLocation(Operation *op, unsigned line, unsigned col)
Register the location, line and column, within the buffer that the given operation was printed at.
const OpPrintingFlags & getPrinterFlags() const
Get the printer flags.
auto getResourcePrinters()
Return the non-dialect resource printers.
LogicalResult pushCyclicPrinting(const void *opaquePointer)
SSANameState & getSSANameState()
Get the state used for SSA names.
DialectInterfaceCollection< OpAsmDialectInterface > & getDialectInterfaces()
Return the dialects within the context that implement OpAsmDialectInterface.
AliasState & getAliasState()
Get the state used for aliases.
void initializeAliases(Operation *op)
Initialize the alias state to enable the printing of aliases.
AsmStateImpl(Operation *op, const OpPrintingFlags &printerFlags, AsmState::LocationMap *locationMap)
DenseMap< Dialect *, SetVector< AsmDialectResourceHandle > > & getDialectResources()
Return the referenced dialect resources within the printer.
AsmStateImpl(MLIRContext *ctx, const OpPrintingFlags &printerFlags, AsmState::LocationMap *locationMap)
DistinctState & getDistinctState()
Get the state used for distinct attribute identifiers.
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-...
Detect if any of the given parameter types has a sub-element handler.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
bool operator<(const Fraction &x, const Fraction &y)
Include the generated interface declarations.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
StringRef toString(AsmResourceEntryKind kind)
bool succeeded(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a success value.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
@ 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,...
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
raw_ostream & operator<<(raw_ostream &os, const AliasResult &result)
This class represents an efficient way to signal success or failure.
This trait is used to determine if a storage user, like Type, is mutable or not.