31 #include "llvm/ADT/APFloat.h"
32 #include "llvm/ADT/ArrayRef.h"
33 #include "llvm/ADT/DenseMap.h"
34 #include "llvm/ADT/MapVector.h"
35 #include "llvm/ADT/STLExtras.h"
36 #include "llvm/ADT/ScopeExit.h"
37 #include "llvm/ADT/ScopedHashTable.h"
38 #include "llvm/ADT/SetVector.h"
39 #include "llvm/ADT/SmallString.h"
40 #include "llvm/ADT/StringExtras.h"
41 #include "llvm/ADT/StringSet.h"
42 #include "llvm/ADT/TypeSwitch.h"
43 #include "llvm/Support/CommandLine.h"
44 #include "llvm/Support/Debug.h"
45 #include "llvm/Support/Endian.h"
46 #include "llvm/Support/ManagedStatic.h"
47 #include "llvm/Support/Regex.h"
48 #include "llvm/Support/SaveAndRestore.h"
49 #include "llvm/Support/Threading.h"
50 #include "llvm/Support/raw_ostream.h"
51 #include <type_traits>
59 #define DEBUG_TYPE "mlir-asm-printer"
79 [&]() {
return parseType(result.emplace_back()); });
95 auto &os = getStream();
99 *this << (operand ? operand.getType() : Type());
115 *this << (result ? result.getType() : Type());
127 #include "mlir/IR/OpAsmInterface.cpp.inc"
131 return entry.
emitError() <<
"unknown 'resource' key '" << entry.
getKey()
132 <<
"' for dialect '" << getDialect()->getNamespace()
144 struct AsmPrinterOptions {
145 llvm::cl::opt<int64_t> printElementsAttrWithHexIfLarger{
146 "mlir-print-elementsattrs-with-hex-if-larger",
148 "Print DenseElementsAttrs with a hex string that have "
149 "more elements than the given upper limit (use -1 to disable)")};
151 llvm::cl::opt<unsigned> elideElementsAttrIfLarger{
152 "mlir-elide-elementsattrs-if-larger",
153 llvm::cl::desc(
"Elide ElementsAttrs with \"...\" that have "
154 "more elements than the given upper limit")};
156 llvm::cl::opt<unsigned> elideResourceStringsIfLarger{
157 "mlir-elide-resource-strings-if-larger",
159 "Elide printing value of resources if string is too long in chars.")};
161 llvm::cl::opt<bool> printDebugInfoOpt{
162 "mlir-print-debuginfo", llvm::cl::init(
false),
163 llvm::cl::desc(
"Print debug info in MLIR output")};
165 llvm::cl::opt<bool> printPrettyDebugInfoOpt{
166 "mlir-pretty-debuginfo", llvm::cl::init(
false),
167 llvm::cl::desc(
"Print pretty debug info in MLIR output")};
171 llvm::cl::opt<bool> printGenericOpFormOpt{
172 "mlir-print-op-generic", llvm::cl::init(
false),
173 llvm::cl::desc(
"Print the generic op form"), llvm::cl::Hidden};
175 llvm::cl::opt<bool> assumeVerifiedOpt{
176 "mlir-print-assume-verified", llvm::cl::init(
false),
177 llvm::cl::desc(
"Skip op verification when using custom printers"),
180 llvm::cl::opt<bool> printLocalScopeOpt{
181 "mlir-print-local-scope", llvm::cl::init(
false),
182 llvm::cl::desc(
"Print with local scope and inline information (eliding "
183 "aliases for attributes, types, and locations")};
185 llvm::cl::opt<bool> skipRegionsOpt{
186 "mlir-print-skip-regions", llvm::cl::init(
false),
187 llvm::cl::desc(
"Skip regions when printing ops.")};
189 llvm::cl::opt<bool> printValueUsers{
190 "mlir-print-value-users", llvm::cl::init(
false),
192 "Print users of operation results and block arguments as a comment")};
194 llvm::cl::opt<bool> printUniqueSSAIDs{
195 "mlir-print-unique-ssa-ids", llvm::cl::init(
false),
196 llvm::cl::desc(
"Print unique SSA ID numbers for values, block arguments "
197 "and naming conflicts across all regions")};
201 static llvm::ManagedStatic<AsmPrinterOptions>
clOptions;
212 : printDebugInfoFlag(false), printDebugInfoPrettyFormFlag(false),
213 printGenericOpFormFlag(false), skipRegionsFlag(false),
214 assumeVerifiedFlag(false), printLocalScope(false),
215 printValueUsersFlag(false), printUniqueSSAIDsFlag(false) {
219 if (
clOptions->elideElementsAttrIfLarger.getNumOccurrences())
220 elementsAttrElementLimit =
clOptions->elideElementsAttrIfLarger;
221 if (
clOptions->printElementsAttrWithHexIfLarger.getNumOccurrences())
222 elementsAttrHexElementLimit =
223 clOptions->printElementsAttrWithHexIfLarger.getValue();
224 if (
clOptions->elideResourceStringsIfLarger.getNumOccurrences())
225 resourceStringCharLimit =
clOptions->elideResourceStringsIfLarger;
226 printDebugInfoFlag =
clOptions->printDebugInfoOpt;
227 printDebugInfoPrettyFormFlag =
clOptions->printPrettyDebugInfoOpt;
228 printGenericOpFormFlag =
clOptions->printGenericOpFormOpt;
229 assumeVerifiedFlag =
clOptions->assumeVerifiedOpt;
230 printLocalScope =
clOptions->printLocalScopeOpt;
231 skipRegionsFlag =
clOptions->skipRegionsOpt;
232 printValueUsersFlag =
clOptions->printValueUsers;
233 printUniqueSSAIDsFlag =
clOptions->printUniqueSSAIDs;
242 elementsAttrElementLimit = largeElementLimit;
248 elementsAttrHexElementLimit = largeElementLimit;
254 resourceStringCharLimit = largeResourceLimit;
262 printDebugInfoFlag = enable;
263 printDebugInfoPrettyFormFlag = prettyForm;
269 printGenericOpFormFlag = enable;
275 skipRegionsFlag = skip;
281 assumeVerifiedFlag =
true;
289 printLocalScope =
true;
295 printValueUsersFlag =
true;
301 return elementsAttrElementLimit &&
302 *elementsAttrElementLimit < int64_t(attr.getNumElements()) &&
303 !llvm::isa<SplatElementsAttr>(attr);
309 return (elementsAttrHexElementLimit != -1) &&
310 (elementsAttrHexElementLimit < int64_t(attr.getNumElements())) &&
311 !llvm::isa<SplatElementsAttr>(attr);
316 return elementsAttrElementLimit;
321 return elementsAttrHexElementLimit;
326 return resourceStringCharLimit;
331 return printDebugInfoFlag;
336 return printDebugInfoPrettyFormFlag;
341 return printGenericOpFormFlag;
349 return assumeVerifiedFlag;
357 return printValueUsersFlag;
373 struct NewLineCounter {
374 unsigned curLine = 1;
377 static raw_ostream &
operator<<(raw_ostream &os, NewLineCounter &newLine) {
396 template <
typename Container,
typename UnaryFunctor>
398 llvm::interleaveComma(c,
os, eachFn);
444 function_ref<
void(
unsigned,
bool)> printValueName =
nullptr);
457 bool withKeyword =
false);
461 bool isTopLevel =
false);
497 function_ref<
void(
unsigned,
bool)> printValueName =
nullptr);
521 SymbolAlias(StringRef name, uint32_t suffixIndex,
bool isType,
523 : name(name), suffixIndex(suffixIndex), isType(isType),
524 isDeferrable(isDeferrable) {}
527 void print(raw_ostream &os)
const {
528 os << (isType ?
"!" :
"#") << name;
534 bool isTypeAlias()
const {
return isType; }
537 bool canBeDeferred()
const {
return isDeferrable; }
543 uint32_t suffixIndex : 30;
547 bool isDeferrable : 1;
553 class AliasInitializer {
557 llvm::BumpPtrAllocator &aliasAllocator)
558 : interfaces(interfaces), aliasAllocator(aliasAllocator),
559 aliasOS(aliasBuffer) {}
562 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias);
570 std::pair<size_t, size_t>
visit(
Attribute attr,
bool canBeDeferred =
false,
571 bool elideType =
false) {
572 return visitImpl(attr, aliases, canBeDeferred, elideType);
579 std::pair<size_t, size_t>
visit(
Type type,
bool canBeDeferred =
false) {
580 return visitImpl(type, aliases, canBeDeferred);
584 struct InProgressAliasInfo {
585 InProgressAliasInfo()
586 : aliasDepth(0), isType(false), canBeDeferred(false) {}
587 InProgressAliasInfo(StringRef alias,
bool isType,
bool canBeDeferred)
588 : alias(alias), aliasDepth(1), isType(isType),
589 canBeDeferred(canBeDeferred) {}
591 bool operator<(
const InProgressAliasInfo &rhs)
const {
593 if (aliasDepth != rhs.aliasDepth)
594 return aliasDepth < rhs.aliasDepth;
595 if (isType != rhs.isType)
597 return alias < rhs.alias;
602 std::optional<StringRef> alias;
605 unsigned aliasDepth : 30;
609 bool canBeDeferred : 1;
619 template <
typename T,
typename... PrintArgs>
620 std::pair<size_t, size_t>
622 llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
623 bool canBeDeferred, PrintArgs &&...printArgs);
626 void markAliasNonDeferrable(
size_t aliasIndex);
630 template <
typename T>
631 void generateAlias(T symbol, InProgressAliasInfo &alias,
bool canBeDeferred);
635 static void initializeAliases(
636 llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
637 llvm::MapVector<const void *, SymbolAlias> &symbolToAlias);
643 llvm::BumpPtrAllocator &aliasAllocator;
646 llvm::MapVector<const void *, InProgressAliasInfo> aliases;
650 llvm::raw_svector_ostream aliasOS;
658 class DummyAliasOperationPrinter :
private OpAsmPrinter {
660 explicit DummyAliasOperationPrinter(
const OpPrintingFlags &printerFlags,
661 AliasInitializer &initializer)
662 : printerFlags(printerFlags), initializer(initializer) {}
666 void printCustomOrGenericOp(
Operation *op)
override {
668 if (printerFlags.shouldPrintDebugInfo())
669 initializer.visit(op->
getLoc(),
true);
672 if (!printerFlags.shouldPrintGenericOpForm()) {
683 void printGenericOp(
Operation *op,
bool printOpName =
true)
override {
685 if (!printerFlags.shouldSkipRegions()) {
699 printAttribute(attr.getValue());
705 void print(
Block *block,
bool printBlockArgs =
true,
706 bool printBlockTerminator =
true) {
709 if (printBlockArgs) {
714 if (printerFlags.shouldPrintDebugInfo())
716 initializer.visit(arg.getLoc(),
false);
724 auto range = llvm::make_range(
726 std::prev(block->
end(),
727 (!hasTerminator || printBlockTerminator) ? 0 : 1));
729 printCustomOrGenericOp(&op);
734 bool printBlockTerminators,
735 bool printEmptyBlock =
false)
override {
738 if (printerFlags.shouldSkipRegions()) {
743 auto *entryBlock = ®ion.
front();
744 print(entryBlock, printEntryBlockArgs, printBlockTerminators);
745 for (
Block &b : llvm::drop_begin(region, 1))
750 bool omitType)
override {
753 if (printerFlags.shouldPrintDebugInfo())
755 initializer.visit(arg.
getLoc(),
false);
759 void printType(
Type type)
override { initializer.visit(type); }
762 void printAttribute(
Attribute attr)
override { initializer.visit(attr); }
763 void printAttributeWithoutType(
Attribute attr)
override {
764 printAttribute(attr);
766 LogicalResult printAlias(
Attribute attr)
override {
767 initializer.visit(attr);
770 LogicalResult printAlias(
Type type)
override {
771 initializer.visit(type);
776 void printOptionalLocationSpecifier(
Location loc)
override {
786 if (elidedAttrs.empty()) {
788 printAttribute(attr.getValue());
791 llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
794 if (!elidedAttrsSet.contains(attr.getName().strref()))
795 printAttribute(attr.getValue());
797 void printOptionalAttrDictWithKeyword(
800 printOptionalAttrDict(attrs, elidedAttrs);
805 raw_ostream &getStream()
const override {
return os; }
809 void printFloat(
const APFloat &)
override {}
810 void printAffineMapOfSSAIds(AffineMapAttr,
ValueRange)
override {}
813 void increaseIndent()
override {}
814 void decreaseIndent()
override {}
815 void printOperand(
Value)
override {}
816 void printOperand(
Value, raw_ostream &os)
override {
825 void printSymbolName(StringRef)
override {}
826 void printSuccessor(
Block *)
override {}
834 AliasInitializer &initializer;
837 mutable llvm::raw_null_ostream os;
842 explicit DummyAliasDialectAsmPrinter(AliasInitializer &initializer,
845 : initializer(initializer), canBeDeferred(canBeDeferred),
846 childIndices(childIndices) {}
851 template <
typename T,
typename... PrintArgs>
852 size_t printAndVisitNestedAliases(T value, PrintArgs &&...printArgs) {
853 printAndVisitNestedAliasesImpl(value, printArgs...);
854 return maxAliasDepth;
860 void printAndVisitNestedAliasesImpl(
Attribute attr,
bool elideType) {
861 if (!isa<BuiltinDialect>(attr.
getDialect())) {
865 }
else if (llvm::isa<AffineMapAttr, DenseArrayAttr, FloatAttr, IntegerAttr,
866 IntegerSetAttr, UnitAttr>(attr)) {
868 }
else if (
auto distinctAttr = dyn_cast<DistinctAttr>(attr)) {
869 printAttribute(distinctAttr.getReferencedAttr());
870 }
else if (
auto dictAttr = dyn_cast<DictionaryAttr>(attr)) {
872 printAttribute(nestedAttr.getName());
873 printAttribute(nestedAttr.getValue());
875 }
else if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr)) {
876 for (
Attribute nestedAttr : arrayAttr.getValue())
877 printAttribute(nestedAttr);
878 }
else if (
auto typeAttr = dyn_cast<TypeAttr>(attr)) {
880 }
else if (
auto locAttr = dyn_cast<OpaqueLoc>(attr)) {
881 printAttribute(locAttr.getFallbackLocation());
882 }
else if (
auto locAttr = dyn_cast<NameLoc>(attr)) {
883 if (!isa<UnknownLoc>(locAttr.getChildLoc()))
884 printAttribute(locAttr.getChildLoc());
885 }
else if (
auto locAttr = dyn_cast<CallSiteLoc>(attr)) {
886 printAttribute(locAttr.getCallee());
887 printAttribute(locAttr.getCaller());
888 }
else if (
auto locAttr = dyn_cast<FusedLoc>(attr)) {
889 if (
Attribute metadata = locAttr.getMetadata())
890 printAttribute(metadata);
891 for (
Location nestedLoc : locAttr.getLocations())
892 printAttribute(nestedLoc);
897 if (
auto typedAttr = llvm::dyn_cast<TypedAttr>(attr)) {
898 Type attrType = typedAttr.getType();
899 if (!llvm::isa<NoneType>(attrType))
904 void printAndVisitNestedAliasesImpl(
Type type) {
909 if (
auto memrefTy = llvm::dyn_cast<MemRefType>(type)) {
911 MemRefLayoutAttrInterface layout = memrefTy.getLayout();
912 if (!llvm::isa<AffineMapAttr>(layout) || !layout.isIdentity())
913 printAttribute(memrefTy.getLayout());
914 if (memrefTy.getMemorySpace())
915 printAttribute(memrefTy.getMemorySpace());
920 auto visitFn = [&](
auto element) {
922 (void)printAlias(element);
929 recordAliasResult(initializer.visit(type, canBeDeferred));
933 void printAttribute(
Attribute attr)
override {
934 recordAliasResult(initializer.visit(attr, canBeDeferred));
936 void printAttributeWithoutType(
Attribute attr)
override {
938 initializer.visit(attr, canBeDeferred,
true));
940 LogicalResult printAlias(
Attribute attr)
override {
941 printAttribute(attr);
944 LogicalResult printAlias(
Type type)
override {
950 void recordAliasResult(std::pair<size_t, size_t> aliasDepthAndIndex) {
951 childIndices.push_back(aliasDepthAndIndex.second);
952 if (aliasDepthAndIndex.first > maxAliasDepth)
953 maxAliasDepth = aliasDepthAndIndex.first;
958 raw_ostream &getStream()
const override {
return os; }
962 void printFloat(
const APFloat &)
override {}
965 void printSymbolName(StringRef)
override {}
968 LogicalResult pushCyclicPrinting(
const void *opaquePointer)
override {
969 return success(cyclicPrintingStack.insert(opaquePointer));
972 void popCyclicPrinting()
override { cyclicPrintingStack.pop_back(); }
979 AliasInitializer &initializer;
988 size_t maxAliasDepth = 0;
991 mutable llvm::raw_null_ostream os;
999 StringRef allowedPunctChars =
"$._-",
1000 bool allowTrailingDigit =
true) {
1001 assert(!name.empty() &&
"Shouldn't have an empty name here");
1003 auto validChar = [&](
char ch) {
1004 return llvm::isAlnum(ch) || allowedPunctChars.contains(ch);
1007 auto copyNameToBuffer = [&] {
1008 for (
char ch : name) {
1010 buffer.push_back(ch);
1012 buffer.push_back(
'_');
1014 buffer.append(llvm::utohexstr((
unsigned char)ch));
1021 if (isdigit(name[0]) || (!validChar(name[0]) && name[0] !=
' ')) {
1022 buffer.push_back(
'_');
1029 if (!allowTrailingDigit && isdigit(name.back())) {
1031 buffer.push_back(
'_');
1036 for (
char ch : name) {
1037 if (!validChar(ch)) {
1049 void AliasInitializer::initializeAliases(
1050 llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
1051 llvm::MapVector<const void *, SymbolAlias> &symbolToAlias) {
1053 unprocessedAliases = visitedSymbols.takeVector();
1054 llvm::stable_sort(unprocessedAliases, [](
const auto &lhs,
const auto &rhs) {
1055 return lhs.second < rhs.second;
1058 llvm::StringMap<unsigned> nameCounts;
1059 for (
auto &[symbol, aliasInfo] : unprocessedAliases) {
1060 if (!aliasInfo.alias)
1062 StringRef alias = *aliasInfo.alias;
1063 unsigned nameIndex = nameCounts[alias]++;
1064 symbolToAlias.insert(
1065 {symbol, SymbolAlias(alias, nameIndex, aliasInfo.isType,
1066 aliasInfo.canBeDeferred)});
1070 void AliasInitializer::initialize(
1072 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias) {
1076 DummyAliasOperationPrinter aliasPrinter(printerFlags, *
this);
1077 aliasPrinter.printCustomOrGenericOp(op);
1080 initializeAliases(aliases, attrTypeToAlias);
1083 template <
typename T,
typename... PrintArgs>
1084 std::pair<size_t, size_t> AliasInitializer::visitImpl(
1085 T value, llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
1086 bool canBeDeferred, PrintArgs &&...printArgs) {
1087 auto [it, inserted] =
1088 aliases.insert({value.getAsOpaquePointer(), InProgressAliasInfo()});
1089 size_t aliasIndex = std::distance(aliases.begin(), it);
1093 markAliasNonDeferrable(aliasIndex);
1094 return {
static_cast<size_t>(it->second.aliasDepth), aliasIndex};
1098 generateAlias(value, it->second, canBeDeferred);
1102 DummyAliasDialectAsmPrinter printer(*
this, canBeDeferred, childAliases);
1103 size_t maxAliasDepth =
1104 printer.printAndVisitNestedAliases(value, printArgs...);
1107 it = std::next(aliases.begin(), aliasIndex);
1110 it->second.childIndices = std::move(childAliases);
1112 it->second.aliasDepth = maxAliasDepth + 1;
1115 return {(size_t)it->second.aliasDepth, aliasIndex};
1118 void AliasInitializer::markAliasNonDeferrable(
size_t aliasIndex) {
1119 auto *it = std::next(aliases.begin(), aliasIndex);
1123 if (!it->second.canBeDeferred)
1126 it->second.canBeDeferred =
false;
1129 for (
size_t childIndex : it->second.childIndices)
1130 markAliasNonDeferrable(childIndex);
1133 template <
typename T>
1134 void AliasInitializer::generateAlias(T symbol, InProgressAliasInfo &alias,
1135 bool canBeDeferred) {
1137 for (
const auto &interface : interfaces) {
1139 interface.getAlias(symbol, aliasOS);
1142 nameBuffer = std::move(aliasBuffer);
1143 assert(!nameBuffer.empty() &&
"expected valid alias name");
1148 if (nameBuffer.empty())
1155 name = name.copy(aliasAllocator);
1156 alias = InProgressAliasInfo(name, std::is_base_of_v<Type, T>,
1175 LogicalResult getAlias(
Attribute attr, raw_ostream &os)
const;
1179 LogicalResult getAlias(
Type ty, raw_ostream &os)
const;
1183 void printNonDeferredAliases(
AsmPrinter::Impl &p, NewLineCounter &newLine) {
1184 printAliases(p, newLine,
false);
1189 printAliases(p, newLine,
true);
1199 llvm::MapVector<const void *, SymbolAlias> attrTypeToAlias;
1202 llvm::BumpPtrAllocator aliasAllocator;
1206 void AliasState::initialize(
1209 AliasInitializer initializer(interfaces, aliasAllocator);
1210 initializer.initialize(op, printerFlags, attrTypeToAlias);
1213 LogicalResult AliasState::getAlias(
Attribute attr, raw_ostream &os)
const {
1215 if (it == attrTypeToAlias.end())
1217 it->second.print(os);
1221 LogicalResult AliasState::getAlias(
Type ty, raw_ostream &os)
const {
1223 if (it == attrTypeToAlias.end())
1226 it->second.print(os);
1230 void AliasState::printAliases(
AsmPrinter::Impl &p, NewLineCounter &newLine,
1232 auto filterFn = [=](
const auto &aliasIt) {
1233 return aliasIt.second.canBeDeferred() == isDeferred;
1235 for (
auto &[opaqueSymbol, alias] :
1236 llvm::make_filter_range(attrTypeToAlias, filterFn)) {
1240 if (alias.isTypeAlias()) {
1273 class SSANameState {
1276 enum :
unsigned { NameSentinel = ~0U };
1279 SSANameState() =
default;
1284 void printValueID(
Value value,
bool printResultNo, raw_ostream &stream)
const;
1287 void printOperationID(
Operation *op, raw_ostream &stream)
const;
1294 BlockInfo getBlockInfo(
Block *block);
1303 void numberValuesInRegion(
Region ®ion);
1304 void numberValuesInBlock(
Block &block);
1311 void getResultIDAndNumber(
OpResult result,
Value &lookupValue,
1312 std::optional<int> &lookupResultNo)
const;
1315 void setValueName(
Value value, StringRef name);
1319 StringRef uniqueValueName(StringRef name);
1342 llvm::ScopedHashTable<StringRef, char> usedNames;
1343 llvm::BumpPtrAllocator usedNameAllocator;
1346 unsigned nextValueID = 0;
1348 unsigned nextArgumentID = 0;
1350 unsigned nextConflictID = 0;
1359 : printerFlags(printerFlags) {
1360 llvm::SaveAndRestore valueIDSaver(nextValueID);
1361 llvm::SaveAndRestore argumentIDSaver(nextArgumentID);
1362 llvm::SaveAndRestore conflictIDSaver(nextConflictID);
1367 using UsedNamesScopeTy = llvm::ScopedHashTable<StringRef, char>::ScopeTy;
1368 using NamingContext =
1369 std::tuple<Region *, unsigned, unsigned, unsigned, UsedNamesScopeTy *>;
1372 llvm::BumpPtrAllocator allocator;
1375 auto *topLevelNamesScope =
1376 new (allocator.Allocate<UsedNamesScopeTy>()) UsedNamesScopeTy(usedNames);
1380 nameContext.push_back(std::make_tuple(®ion, nextValueID, nextArgumentID,
1381 nextConflictID, topLevelNamesScope));
1383 numberValuesInOp(*op);
1385 while (!nameContext.empty()) {
1387 UsedNamesScopeTy *parentScope;
1391 std::tie(region, std::ignore, std::ignore, std::ignore, parentScope) =
1392 nameContext.pop_back_val();
1394 std::tie(region, nextValueID, nextArgumentID, nextConflictID,
1395 parentScope) = nameContext.pop_back_val();
1399 while (usedNames.getCurScope() != parentScope) {
1400 usedNames.getCurScope()->~UsedNamesScopeTy();
1401 assert((usedNames.getCurScope() !=
nullptr || parentScope ==
nullptr) &&
1402 "top level parentScope must be a nullptr");
1406 auto *curNamesScope =
new (allocator.Allocate<UsedNamesScopeTy>())
1407 UsedNamesScopeTy(usedNames);
1409 numberValuesInRegion(*region);
1413 nameContext.push_back(std::make_tuple(®ion, nextValueID,
1414 nextArgumentID, nextConflictID,
1419 while (usedNames.getCurScope() !=
nullptr)
1420 usedNames.getCurScope()->~UsedNamesScopeTy();
1423 void SSANameState::printValueID(
Value value,
bool printResultNo,
1424 raw_ostream &stream)
const {
1426 stream <<
"<<NULL VALUE>>";
1430 std::optional<int> resultNo;
1431 auto lookupValue = value;
1435 if (
OpResult result = dyn_cast<OpResult>(value))
1436 getResultIDAndNumber(result, lookupValue, resultNo);
1438 auto it = valueIDs.find(lookupValue);
1439 if (it == valueIDs.end()) {
1440 stream <<
"<<UNKNOWN SSA VALUE>>";
1445 if (it->second != NameSentinel) {
1446 stream << it->second;
1448 auto nameIt = valueNames.find(lookupValue);
1449 assert(nameIt != valueNames.end() &&
"Didn't have a name entry?");
1450 stream << nameIt->second;
1453 if (resultNo && printResultNo)
1454 stream <<
'#' << *resultNo;
1457 void SSANameState::printOperationID(
Operation *op, raw_ostream &stream)
const {
1458 auto it = operationIDs.find(op);
1459 if (it == operationIDs.end()) {
1460 stream <<
"<<UNKNOWN OPERATION>>";
1462 stream <<
'%' << it->second;
1467 auto it = opResultGroups.find(op);
1468 return it == opResultGroups.end() ?
ArrayRef<int>() : it->second;
1471 BlockInfo SSANameState::getBlockInfo(
Block *block) {
1472 auto it = blockNames.find(block);
1473 BlockInfo invalidBlock{-1,
"INVALIDBLOCK"};
1474 return it != blockNames.end() ? it->second : invalidBlock;
1477 void SSANameState::shadowRegionArgs(
Region ®ion,
ValueRange namesToUse) {
1478 assert(!region.
empty() &&
"cannot shadow arguments of an empty region");
1480 "incorrect number of names passed in");
1482 "only KnownIsolatedFromAbove ops can shadow names");
1485 for (
unsigned i = 0, e = namesToUse.size(); i != e; ++i) {
1486 auto nameToUse = namesToUse[i];
1487 if (nameToUse ==
nullptr)
1492 llvm::raw_svector_ostream nameStream(nameStr);
1493 printValueID(nameToUse,
true, nameStream);
1496 assert(valueIDs[nameToReplace] == NameSentinel);
1499 auto name = StringRef(nameStream.str()).drop_front();
1502 valueNames[nameToReplace] = name.copy(usedNameAllocator);
1506 void SSANameState::numberValuesInRegion(
Region ®ion) {
1507 auto setBlockArgNameFn = [&](
Value arg, StringRef name) {
1508 assert(!valueIDs.count(arg) &&
"arg numbered multiple times");
1509 assert(llvm::cast<BlockArgument>(arg).getOwner()->getParent() == ®ion &&
1510 "arg not defined in current region");
1511 setValueName(arg, name);
1516 if (
auto asmInterface = dyn_cast<OpAsmOpInterface>(op))
1517 asmInterface.getAsmBlockArgumentNames(region, setBlockArgNameFn);
1522 unsigned nextBlockID = 0;
1523 for (
auto &block : region) {
1526 auto blockInfoIt = blockNames.insert({&block, {-1,
""}});
1527 if (blockInfoIt.second) {
1531 llvm::raw_string_ostream(name) <<
"^bb" << nextBlockID;
1532 blockInfoIt.first->second.name = StringRef(name).copy(usedNameAllocator);
1534 blockInfoIt.first->second.ordering = nextBlockID++;
1536 numberValuesInBlock(block);
1540 void SSANameState::numberValuesInBlock(
Block &block) {
1545 llvm::raw_svector_ostream specialName(specialNameBuffer);
1547 if (valueIDs.count(arg))
1550 specialNameBuffer.resize(strlen(
"arg"));
1551 specialName << nextArgumentID++;
1553 setValueName(arg, specialName.str());
1557 for (
auto &op : block)
1558 numberValuesInOp(op);
1561 void SSANameState::numberValuesInOp(
Operation &op) {
1564 auto setResultNameFn = [&](
Value result, StringRef name) {
1565 assert(!valueIDs.count(result) &&
"result numbered multiple times");
1566 assert(result.
getDefiningOp() == &op &&
"result not defined by 'op'");
1567 setValueName(result, name);
1570 if (
int resultNo = llvm::cast<OpResult>(result).getResultNumber())
1571 resultGroups.push_back(resultNo);
1574 auto setBlockNameFn = [&](
Block *block, StringRef name) {
1576 "getAsmBlockArgumentNames callback invoked on a block not directly "
1577 "nested under the current operation");
1578 assert(!blockNames.count(block) &&
"block numbered multiple times");
1581 if (name.data() != tmpBuffer.data()) {
1582 tmpBuffer.append(name);
1583 name = tmpBuffer.str();
1585 name = name.copy(usedNameAllocator);
1586 blockNames[block] = {-1, name};
1590 if (OpAsmOpInterface asmInterface = dyn_cast<OpAsmOpInterface>(&op)) {
1591 asmInterface.getAsmBlockNames(setBlockNameFn);
1592 asmInterface.getAsmResultNames(setResultNameFn);
1597 if (numResults == 0) {
1600 if (operationIDs.try_emplace(&op, nextValueID).second)
1608 if (valueIDs.try_emplace(resultBegin, nextValueID).second)
1612 if (resultGroups.size() != 1) {
1613 llvm::array_pod_sort(resultGroups.begin(), resultGroups.end());
1614 opResultGroups.try_emplace(&op, std::move(resultGroups));
1618 void SSANameState::getResultIDAndNumber(
1620 std::optional<int> &lookupResultNo)
const {
1628 auto resultGroupIt = opResultGroups.find(owner);
1629 if (resultGroupIt == opResultGroups.end()) {
1631 lookupResultNo = resultNo;
1638 const auto *it = llvm::upper_bound(resultGroups, resultNo);
1639 int groupResultNo = 0, groupSize = 0;
1642 if (it == resultGroups.end()) {
1643 groupResultNo = resultGroups.back();
1644 groupSize =
static_cast<int>(owner->
getNumResults()) - resultGroups.back();
1647 groupResultNo = *std::prev(it);
1648 groupSize = *it - groupResultNo;
1653 lookupResultNo = resultNo - groupResultNo;
1654 lookupValue = owner->
getResult(groupResultNo);
1657 void SSANameState::setValueName(
Value value, StringRef name) {
1660 valueIDs[value] = nextValueID++;
1664 valueIDs[value] = NameSentinel;
1665 valueNames[value] = uniqueValueName(name);
1668 StringRef SSANameState::uniqueValueName(StringRef name) {
1673 if (!usedNames.count(name)) {
1674 name = name.copy(usedNameAllocator);
1680 probeName.push_back(
'_');
1682 probeName += llvm::utostr(nextConflictID++);
1683 if (!usedNames.count(probeName)) {
1684 name = probeName.str().copy(usedNameAllocator);
1687 probeName.resize(name.size() + 1);
1691 usedNames.insert(name,
char());
1701 class DistinctState {
1707 uint64_t distinctCounter = 0;
1712 uint64_t DistinctState::getId(
DistinctAttr distinctAttr) {
1713 auto [it, inserted] =
1714 distinctAttrMap.try_emplace(distinctAttr, distinctCounter);
1717 return it->getSecond();
1724 AsmParsedResourceEntry::~AsmParsedResourceEntry() =
default;
1725 AsmResourceBuilder::~AsmResourceBuilder() =
default;
1726 AsmResourceParser::~AsmResourceParser() =
default;
1727 AsmResourcePrinter::~AsmResourcePrinter() =
default;
1731 case AsmResourceEntryKind::Blob:
1733 case AsmResourceEntryKind::Bool:
1735 case AsmResourceEntryKind::String:
1738 llvm_unreachable(
"unknown AsmResourceEntryKind");
1742 std::unique_ptr<ResourceCollection> &collection = keyToResources[key.str()];
1744 collection = std::make_unique<ResourceCollection>(key);
1748 std::vector<std::unique_ptr<AsmResourcePrinter>>
1750 std::vector<std::unique_ptr<AsmResourcePrinter>> printers;
1751 for (
auto &it : keyToResources) {
1752 ResourceCollection *collection = it.second.get();
1754 return collection->buildResources(op, builder);
1756 printers.emplace_back(
1762 LogicalResult FallbackAsmResourceMap::ResourceCollection::parseResource(
1766 FailureOr<AsmResourceBlob> blob = entry.
parseAsBlob();
1769 resources.emplace_back(entry.
getKey(), std::move(*blob));
1776 resources.emplace_back(entry.
getKey(), *value);
1783 resources.emplace_back(entry.
getKey(), std::move(*str));
1790 void FallbackAsmResourceMap::ResourceCollection::buildResources(
1792 for (
const auto &entry : resources) {
1793 if (
const auto *value = std::get_if<AsmResourceBlob>(&entry.value))
1795 else if (
const auto *value = std::get_if<bool>(&entry.value))
1797 else if (
const auto *value = std::get_if<std::string>(&entry.value))
1800 llvm_unreachable(
"unknown AsmResourceEntryKind");
1814 : interfaces(op->
getContext()), nameState(op, printerFlags),
1815 printerFlags(printerFlags), locationMap(locationMap) {}
1818 : interfaces(ctx), printerFlags(printerFlags), locationMap(locationMap) {}
1822 aliasState.initialize(op, printerFlags, interfaces);
1842 return llvm::make_pointee_range(externalResourcePrinters);
1852 (*locationMap)[op] = std::make_pair(line, col);
1858 return dialectResources;
1862 return success(cyclicPrintingStack.insert(opaquePointer));
1878 AliasState aliasState;
1881 SSANameState nameState;
1884 DistinctState distinctState;
1900 template <
typename Range>
1904 [&stream](
const auto &dimSize) {
1905 if (ShapedType::isDynamic(dimSize))
1923 return printerFlags;
1927 auto parentThreadId = llvm::get_threadid();
1929 if (parentThreadId == llvm::get_threadid()) {
1931 diag.print(llvm::dbgs());
1932 llvm::dbgs() <<
"\n";
1938 if (failed(
verify(op))) {
1939 LLVM_DEBUG(llvm::dbgs()
1941 <<
"' failed to verify and will be printed in generic form\n");
1945 return printerFlags;
1964 return impl->getPrinterFlags();
1968 std::unique_ptr<AsmResourcePrinter> printer) {
1969 impl->externalResourcePrinters.emplace_back(std::move(printer));
1974 return impl->getDialectResources();
1982 : os(os), state(state), printerFlags(state.getPrinterFlags()) {}
1990 printLocation(loc, allowAlias);
1996 if (!isTopLevel && succeeded(state.getAliasState().getAlias(loc, os)))
2000 .Case<OpaqueLoc>([&](OpaqueLoc loc) {
2001 printLocationInternal(loc.getFallbackLocation(), pretty);
2003 .Case<UnknownLoc>([&](UnknownLoc loc) {
2009 .Case<FileLineColLoc>([&](FileLineColLoc loc) {
2011 os << loc.getFilename().getValue();
2013 printEscapedString(loc.getFilename());
2014 os <<
':' << loc.getLine() <<
':' << loc.getColumn();
2016 .Case<NameLoc>([&](NameLoc loc) {
2017 printEscapedString(loc.getName());
2020 auto childLoc = loc.getChildLoc();
2021 if (!llvm::isa<UnknownLoc>(childLoc)) {
2023 printLocationInternal(childLoc, pretty);
2027 .Case<CallSiteLoc>([&](CallSiteLoc loc) {
2032 printLocationInternal(callee, pretty);
2034 if (llvm::isa<NameLoc>(callee)) {
2035 if (llvm::isa<FileLineColLoc>(caller)) {
2038 os << newLine <<
" at ";
2041 os << newLine <<
" at ";
2046 printLocationInternal(caller, pretty);
2050 .Case<FusedLoc>([&](
FusedLoc loc) {
2053 if (
Attribute metadata = loc.getMetadata()) {
2061 [&](Location loc) { printLocationInternal(loc, pretty); },
2062 [&]() { os << ", "; });
2069 static void printFloatValue(const APFloat &apValue, raw_ostream &os,
2070 bool *printedHex = nullptr) {
2071 // We would like to output the FP constant value in exponential notation,
2072 // but we cannot do this if doing so will lose precision. Check here to
2073 // make sure that we only output it in exponential format if we can parse
2074 // the value back and get the same value.
2075 bool isInf = apValue.isInfinity();
2076 bool isNaN = apValue.isNaN();
2077 if (!isInf && !isNaN) {
2078 SmallString<128> strValue;
2079 apValue.toString(strValue, /*FormatPrecision=*/6, /*FormatMaxPadding=*/0,
2080 /*TruncateZero=*/false);
2082 // Check to make sure that the stringized number is not some string like
2083 // "Inf" or NaN, that atof will accept, but the lexer will not. Check
2084 // that the string matches the "[-+]?[0-9]" regex.
2085 assert(((strValue[0] >= '0
' && strValue[0] <= '9') ||
2086 ((strValue[0] ==
'-' || strValue[0] ==
'+') &&
2087 (strValue[1] >=
'0' && strValue[1] <=
'9'))) &&
2088 "[-+]?[0-9] regex does not match!");
2092 if (APFloat(apValue.getSemantics(), strValue).bitwiseIsEqual(apValue)) {
2100 apValue.toString(strValue);
2103 if (strValue.str().contains(
'.')) {
2114 APInt apInt = apValue.bitcastToAPInt();
2115 apInt.toString(str, 16,
false,
2122 return printLocationInternal(loc,
true,
true);
2126 printLocationInternal(loc,
false,
true);
2134 state.getDialectResources()[resource.
getDialect()].insert(resource);
2142 if (symName.empty() || !isalpha(symName.front()))
2147 symName = symName.drop_while(
2148 [](
char c) {
return llvm::isAlnum(c) || c ==
'.' || c ==
'_'; });
2149 if (symName.empty())
2154 return symName.front() ==
'<' && symName.back() ==
'>';
2159 StringRef dialectName, StringRef symString) {
2160 os << symPrefix << dialectName;
2165 os <<
'.' << symString;
2169 os << '<' << symString << '>
';
2173 static bool isBareIdentifier(StringRef name) {
2174 // By making this unsigned, the value passed in to isalnum will always be
2175 // in the range 0-255. This is important when building with MSVC because
2176 // its implementation will assert. This situation can arise when dealing
2177 // with UTF-8 multibyte characters.
2178 if (name.empty() || (!isalpha(name[0]) && name[0] != '_
'))
2180 return llvm::all_of(name.drop_front(), [](unsigned char c) {
2181 return isalnum(c) || c == '_
' || c == '$
' || c == '.
';
2187 static void printKeywordOrString(StringRef keyword, raw_ostream &os) {
2188 // If it can be represented as a bare identifier, write it directly.
2189 if (isBareIdentifier(keyword)) {
2194 // Otherwise, output the keyword wrapped in quotes with proper escaping.
2196 printEscapedString(keyword, os);
2203 static void printSymbolReference(StringRef symbolRef, raw_ostream &os) {
2204 if (symbolRef.empty()) {
2205 os << "@<<INVALID EMPTY SYMBOL>>
";
2209 printKeywordOrString(symbolRef, os);
2212 // Print out a valid ElementsAttr that is succinct and can represent any
2213 // potential shape/type, for use when eliding a large ElementsAttr.
2215 // We choose to use a dense resource ElementsAttr literal with conspicuous
2216 // content to hopefully alert readers to the fact that this has been elided.
2217 static void printElidedElementsAttr(raw_ostream &os) {
2218 os << R"(dense_resource<__elided__>)
";
2221 LogicalResult AsmPrinter::Impl::printAlias(Attribute attr) {
2222 return state.getAliasState().getAlias(attr, os);
2225 LogicalResult AsmPrinter::Impl::printAlias(Type type) {
2226 return state.getAliasState().getAlias(type, os);
2229 void AsmPrinter::Impl::printAttribute(Attribute attr,
2230 AttrTypeElision typeElision) {
2232 os << "<<NULL ATTRIBUTE>>
";
2236 // Try to print an alias for this attribute.
2237 if (succeeded(printAlias(attr)))
2239 return printAttributeImpl(attr, typeElision);
2242 void AsmPrinter::Impl::printAttributeImpl(Attribute attr,
2243 AttrTypeElision typeElision) {
2244 if (!isa<BuiltinDialect>(attr.getDialect())) {
2245 printDialectAttribute(attr);
2246 } else if (auto opaqueAttr = llvm::dyn_cast<OpaqueAttr>(attr)) {
2247 printDialectSymbol(os, "#
", opaqueAttr.getDialectNamespace(),
2248 opaqueAttr.getAttrData());
2249 } else if (llvm::isa<UnitAttr>(attr)) {
2252 } else if (auto distinctAttr = llvm::dyn_cast<DistinctAttr>(attr)) {
2253 os << "distinct[
" << state.getDistinctState().getId(distinctAttr) << "]<
";
2254 if (!llvm::isa<UnitAttr>(distinctAttr.getReferencedAttr())) {
2255 printAttribute(distinctAttr.getReferencedAttr());
2259 } else if (auto dictAttr = llvm::dyn_cast<DictionaryAttr>(attr)) {
2261 interleaveComma(dictAttr.getValue(),
2262 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2265 } else if (auto intAttr = llvm::dyn_cast<IntegerAttr>(attr)) {
2266 Type intType = intAttr.getType();
2267 if (intType.isSignlessInteger(1)) {
2268 os << (intAttr.getValue().getBoolValue() ? "true" : "false");
2270 // Boolean integer attributes always elides the type.
2274 // Only print attributes as unsigned if they are explicitly unsigned or are
2275 // signless 1-bit values. Indexes, signed values, and multi-bit signless
2276 // values print as signed.
2278 intType.isUnsignedInteger() || intType.isSignlessInteger(1);
2279 intAttr.getValue().print(os, !isUnsigned);
2281 // IntegerAttr elides the type if I64.
2282 if (typeElision == AttrTypeElision::May && intType.isSignlessInteger(64))
2285 } else if (auto floatAttr = llvm::dyn_cast<FloatAttr>(attr)) {
2286 bool printedHex = false;
2287 printFloatValue(floatAttr.getValue(), os, &printedHex);
2289 // FloatAttr elides the type if F64.
2290 if (typeElision == AttrTypeElision::May && floatAttr.getType().isF64() &&
2294 } else if (auto strAttr = llvm::dyn_cast<StringAttr>(attr)) {
2295 printEscapedString(strAttr.getValue());
2297 } else if (auto arrayAttr = llvm::dyn_cast<ArrayAttr>(attr)) {
2299 interleaveComma(arrayAttr.getValue(), [&](Attribute attr) {
2300 printAttribute(attr, AttrTypeElision::May);
2304 } else if (auto affineMapAttr = llvm::dyn_cast<AffineMapAttr>(attr)) {
2305 os << "affine_map<
";
2306 affineMapAttr.getValue().print(os);
2309 // AffineMap always elides the type.
2312 } else if (auto integerSetAttr = llvm::dyn_cast<IntegerSetAttr>(attr)) {
2313 os << "affine_set<
";
2314 integerSetAttr.getValue().print(os);
2317 // IntegerSet always elides the type.
2320 } else if (auto typeAttr = llvm::dyn_cast<TypeAttr>(attr)) {
2321 printType(typeAttr.getValue());
2323 } else if (auto refAttr = llvm::dyn_cast<SymbolRefAttr>(attr)) {
2324 printSymbolReference(refAttr.getRootReference().getValue(), os);
2325 for (FlatSymbolRefAttr nestedRef : refAttr.getNestedReferences()) {
2327 printSymbolReference(nestedRef.getValue(), os);
2330 } else if (auto intOrFpEltAttr =
2331 llvm::dyn_cast<DenseIntOrFPElementsAttr>(attr)) {
2332 if (printerFlags.shouldElideElementsAttr(intOrFpEltAttr)) {
2333 printElidedElementsAttr(os);
2336 printDenseIntOrFPElementsAttr(intOrFpEltAttr, /*allowHex=*/true);
2340 } else if (auto strEltAttr = llvm::dyn_cast<DenseStringElementsAttr>(attr)) {
2341 if (printerFlags.shouldElideElementsAttr(strEltAttr)) {
2342 printElidedElementsAttr(os);
2345 printDenseStringElementsAttr(strEltAttr);
2349 } else if (auto sparseEltAttr = llvm::dyn_cast<SparseElementsAttr>(attr)) {
2350 if (printerFlags.shouldElideElementsAttr(sparseEltAttr.getIndices()) ||
2351 printerFlags.shouldElideElementsAttr(sparseEltAttr.getValues())) {
2352 printElidedElementsAttr(os);
2355 DenseIntElementsAttr indices = sparseEltAttr.getIndices();
2356 if (indices.getNumElements() != 0) {
2357 printDenseIntOrFPElementsAttr(indices, /*allowHex=*/false);
2359 printDenseElementsAttr(sparseEltAttr.getValues(), /*allowHex=*/true);
2363 } else if (auto stridedLayoutAttr = llvm::dyn_cast<StridedLayoutAttr>(attr)) {
2364 stridedLayoutAttr.print(os);
2365 } else if (auto denseArrayAttr = llvm::dyn_cast<DenseArrayAttr>(attr)) {
2367 printType(denseArrayAttr.getElementType());
2368 if (!denseArrayAttr.empty()) {
2370 printDenseArrayAttr(denseArrayAttr);
2374 } else if (auto resourceAttr =
2375 llvm::dyn_cast<DenseResourceElementsAttr>(attr)) {
2376 os << "dense_resource<
";
2377 printResourceHandle(resourceAttr.getRawHandle());
2379 } else if (auto locAttr = llvm::dyn_cast<LocationAttr>(attr)) {
2380 printLocation(locAttr);
2382 llvm::report_fatal_error("Unknown builtin attribute
");
2384 // Don't print the type if we must elide it, or if it is a None type.
2385 if (typeElision != AttrTypeElision::Must) {
2386 if (auto typedAttr = llvm::dyn_cast<TypedAttr>(attr)) {
2387 Type attrType = typedAttr.getType();
2388 if (!llvm::isa<NoneType>(attrType)) {
2390 printType(attrType);
2397 static void printDenseIntElement(const APInt &value, raw_ostream &os,
2399 if (type.isInteger(1))
2400 os << (value.getBoolValue() ? "
true" : "false");
2402 value.print(os, !type.isUnsignedInteger());
2406 printDenseElementsAttrImpl(bool isSplat, ShapedType type, raw_ostream &os,
2407 function_ref<void(unsigned)> printEltFn) {
2408 // Special case for 0-d and splat tensors.
2410 return printEltFn(0);
2412 // Special case for degenerate tensors.
2413 auto numElements = type.getNumElements();
2414 if (numElements == 0)
2417 // We use a mixed-radix counter to iterate through the shape. When we bump a
2418 // non-least-significant digit, we emit a close bracket. When we next emit an
2419 // element we re-open all closed brackets.
2421 // The mixed-radix counter, with radices in 'shape'.
2422 int64_t rank = type.getRank();
2423 SmallVector<unsigned, 4> counter(rank, 0);
2424 // The number of brackets that have been opened and not closed.
2425 unsigned openBrackets = 0;
2427 auto shape = type.getShape();
2428 auto bumpCounter = [&] {
2429 // Bump the least significant digit.
2430 ++counter[rank - 1];
2431 // Iterate backwards bubbling back the increment.
2432 for (unsigned i = rank - 1; i > 0; --i)
2433 if (counter[i] >= shape[i]) {
2434 // Index 'i' is rolled over. Bump (i-1) and close a bracket.
2442 for (unsigned idx = 0, e = numElements; idx != e; ++idx) {
2445 while (openBrackets++ < rank)
2447 openBrackets = rank;
2451 while (openBrackets-- > 0)
2455 void AsmPrinter::Impl::printDenseElementsAttr(DenseElementsAttr attr,
2457 if (auto stringAttr = llvm::dyn_cast<DenseStringElementsAttr>(attr))
2458 return printDenseStringElementsAttr(stringAttr);
2460 printDenseIntOrFPElementsAttr(llvm::cast<DenseIntOrFPElementsAttr>(attr),
2464 void AsmPrinter::Impl::printDenseIntOrFPElementsAttr(
2465 DenseIntOrFPElementsAttr attr, bool allowHex) {
2466 auto type = attr.getType();
2467 auto elementType = type.getElementType();
2469 // Check to see if we should format this attribute as a hex string.
2470 if (allowHex && printerFlags.shouldPrintElementsAttrWithHex(attr)) {
2471 ArrayRef<char> rawData = attr.getRawData();
2472 if (llvm::endianness::native == llvm::endianness::big) {
2473 // Convert endianess in big-endian(BE) machines. `rawData` is BE in BE
2474 // machines. It is converted here to print in LE format.
2475 SmallVector<char, 64> outDataVec(rawData.size());
2476 MutableArrayRef<char> convRawData(outDataVec);
2477 DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
2478 rawData, convRawData, type);
2479 printHexString(convRawData);
2481 printHexString(rawData);
2487 if (ComplexType complexTy = llvm::dyn_cast<ComplexType>(elementType)) {
2488 Type complexElementType = complexTy.getElementType();
2489 // Note: The if and else below had a common lambda function which invoked
2490 // printDenseElementsAttrImpl. This lambda was hitting a bug in gcc 9.1,9.2
2491 // and hence was replaced.
2492 if (llvm::isa<IntegerType>(complexElementType)) {
2493 auto valueIt = attr.value_begin<std::complex<APInt>>();
2494 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2495 auto complexValue = *(valueIt + index);
2497 printDenseIntElement(complexValue.real(), os, complexElementType);
2499 printDenseIntElement(complexValue.imag(), os, complexElementType);
2503 auto valueIt = attr.value_begin<std::complex<APFloat>>();
2504 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2505 auto complexValue = *(valueIt + index);
2507 printFloatValue(complexValue.real(), os);
2509 printFloatValue(complexValue.imag(), os);
2513 } else if (elementType.isIntOrIndex()) {
2514 auto valueIt = attr.value_begin<APInt>();
2515 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2516 printDenseIntElement(*(valueIt + index), os, elementType);
2519 assert(llvm::isa<FloatType>(elementType) && "unexpected element type
");
2520 auto valueIt = attr.value_begin<APFloat>();
2521 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2522 printFloatValue(*(valueIt + index), os);
2527 void AsmPrinter::Impl::printDenseStringElementsAttr(
2528 DenseStringElementsAttr attr) {
2529 ArrayRef<StringRef> data = attr.getRawStringData();
2530 auto printFn = [&](unsigned index) { printEscapedString(data[index]); };
2531 printDenseElementsAttrImpl(attr.isSplat(), attr.getType(), os, printFn);
2534 void AsmPrinter::Impl::printDenseArrayAttr(DenseArrayAttr attr) {
2535 Type type = attr.getElementType();
2536 unsigned bitwidth = type.isInteger(1) ? 8 : type.getIntOrFloatBitWidth();
2537 unsigned byteSize = bitwidth / 8;
2538 ArrayRef<char> data = attr.getRawData();
2540 auto printElementAt = [&](unsigned i) {
2541 APInt value(bitwidth, 0);
2543 llvm::LoadIntFromMemory(
2544 value, reinterpret_cast<const uint8_t *>(data.begin() + byteSize * i),
2547 // Print the data as-is or as a float.
2548 if (type.isIntOrIndex()) {
2549 printDenseIntElement(value, getStream(), type);
2551 APFloat fltVal(llvm::cast<FloatType>(type).getFloatSemantics(), value);
2552 printFloatValue(fltVal, getStream());
2555 llvm::interleaveComma(llvm::seq<unsigned>(0, attr.size()), getStream(),
2559 void AsmPrinter::Impl::printType(Type type) {
2561 os << "<<NULL TYPE>>
";
2565 // Try to print an alias for this type.
2566 if (succeeded(printAlias(type)))
2568 return printTypeImpl(type);
2571 void AsmPrinter::Impl::printTypeImpl(Type type) {
2572 TypeSwitch<Type>(type)
2573 .Case<OpaqueType>([&](OpaqueType opaqueTy) {
2574 printDialectSymbol(os, "!
", opaqueTy.getDialectNamespace(),
2575 opaqueTy.getTypeData());
2577 .Case<IndexType>([&](Type) { os << "index
"; })
2578 .Case<Float8E5M2Type>([&](Type) { os << "f8E5M2
"; })
2579 .Case<Float8E4M3Type>([&](Type) { os << "f8E4M3
"; })
2580 .Case<Float8E4M3FNType>([&](Type) { os << "f8E4M3FN
"; })
2581 .Case<Float8E5M2FNUZType>([&](Type) { os << "f8E5M2FNUZ
"; })
2582 .Case<Float8E4M3FNUZType>([&](Type) { os << "f8E4M3FNUZ
"; })
2583 .Case<Float8E4M3B11FNUZType>([&](Type) { os << "f8E4M3B11FNUZ
"; })
2584 .Case<BFloat16Type>([&](Type) { os << "bf16"; })
2585 .Case<Float16Type>([&](Type) { os << "f16"; })
2586 .Case<FloatTF32Type>([&](Type) { os << "tf32
"; })
2587 .Case<Float32Type>([&](Type) { os << "f32
"; })
2588 .Case<Float64Type>([&](Type) { os << "f64
"; })
2589 .Case<Float80Type>([&](Type) { os << "f80
"; })
2590 .Case<Float128Type>([&](Type) { os << "f128
"; })
2591 .Case<IntegerType>([&](IntegerType integerTy) {
2592 if (integerTy.isSigned())
2594 else if (integerTy.isUnsigned())
2596 os << 'i' << integerTy.getWidth();
2598 .Case<FunctionType>([&](FunctionType funcTy) {
2600 interleaveComma(funcTy.getInputs(), [&](Type ty) { printType(ty); });
2602 ArrayRef<Type> results = funcTy.getResults();
2603 if (results.size() == 1 && !llvm::isa<FunctionType>(results[0])) {
2604 printType(results[0]);
2607 interleaveComma(results, [&](Type ty) { printType(ty); });
2611 .Case<VectorType>([&](VectorType vectorTy) {
2612 auto scalableDims = vectorTy.getScalableDims();
2614 auto vShape = vectorTy.getShape();
2615 unsigned lastDim = vShape.size();
2616 unsigned dimIdx = 0;
2617 for (dimIdx = 0; dimIdx < lastDim; dimIdx++) {
2618 if (!scalableDims.empty() && scalableDims[dimIdx])
2620 os << vShape[dimIdx];
2621 if (!scalableDims.empty() && scalableDims[dimIdx])
2625 printType(vectorTy.getElementType());
2628 .Case<RankedTensorType>([&](RankedTensorType tensorTy) {
2630 printDimensionList(tensorTy.getShape());
2631 if (!tensorTy.getShape().empty())
2633 printType(tensorTy.getElementType());
2634 // Only print the encoding attribute value if set.
2635 if (tensorTy.getEncoding()) {
2637 printAttribute(tensorTy.getEncoding());
2641 .Case<UnrankedTensorType>([&](UnrankedTensorType tensorTy) {
2643 printType(tensorTy.getElementType());
2646 .Case<MemRefType>([&](MemRefType memrefTy) {
2648 printDimensionList(memrefTy.getShape());
2649 if (!memrefTy.getShape().empty())
2651 printType(memrefTy.getElementType());
2652 MemRefLayoutAttrInterface layout = memrefTy.getLayout();
2653 if (!llvm::isa<AffineMapAttr>(layout) || !layout.isIdentity()) {
2655 printAttribute(memrefTy.getLayout(), AttrTypeElision::May);
2657 // Only print the memory space if it is the non-default one.
2658 if (memrefTy.getMemorySpace()) {
2660 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2664 .Case<UnrankedMemRefType>([&](UnrankedMemRefType memrefTy) {
2666 printType(memrefTy.getElementType());
2667 // Only print the memory space if it is the non-default one.
2668 if (memrefTy.getMemorySpace()) {
2670 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2674 .Case<ComplexType>([&](ComplexType complexTy) {
2676 printType(complexTy.getElementType());
2679 .Case<TupleType>([&](TupleType tupleTy) {
2681 interleaveComma(tupleTy.getTypes(),
2682 [&](Type type) { printType(type); });
2685 .Case<NoneType>([&](Type) { os << "none
"; })
2686 .Default([&](Type type) { return printDialectType(type); });
2689 void AsmPrinter::Impl::printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
2690 ArrayRef<StringRef> elidedAttrs,
2692 // If there are no attributes, then there is nothing to be done.
2696 // Functor used to print a filtered attribute list.
2697 auto printFilteredAttributesFn = [&](auto filteredAttrs) {
2698 // Print the 'attributes' keyword if necessary.
2700 os << " attributes
";
2702 // Otherwise, print them all out in braces.
2704 interleaveComma(filteredAttrs,
2705 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2709 // If no attributes are elided, we can directly print with no filtering.
2710 if (elidedAttrs.empty())
2711 return printFilteredAttributesFn(attrs);
2713 // Otherwise, filter out any attributes that shouldn't be included.
2714 llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
2716 auto filteredAttrs = llvm::make_filter_range(attrs, [&](NamedAttribute attr) {
2717 return !elidedAttrsSet.contains(attr.getName().strref());
2719 if (!filteredAttrs.empty())
2720 printFilteredAttributesFn(filteredAttrs);
2722 void AsmPrinter::Impl::printNamedAttribute(NamedAttribute attr) {
2723 // Print the name without quotes if possible.
2724 ::printKeywordOrString(attr.getName().strref(), os);
2726 // Pretty printing elides the attribute value for unit attributes.
2727 if (llvm::isa<UnitAttr>(attr.getValue()))
2731 printAttribute(attr.getValue());
2734 void AsmPrinter::Impl::printDialectAttribute(Attribute attr) {
2735 auto &dialect = attr.getDialect();
2737 // Ask the dialect to serialize the attribute to a string.
2738 std::string attrName;
2740 llvm::raw_string_ostream attrNameStr(attrName);
2741 Impl subPrinter(attrNameStr, state);
2742 DialectAsmPrinter printer(subPrinter);
2743 dialect.printAttribute(attr, printer);
2745 printDialectSymbol(os, "#
", dialect.getNamespace(), attrName);
2748 void AsmPrinter::Impl::printDialectType(Type type) {
2749 auto &dialect = type.getDialect();
2751 // Ask the dialect to serialize the type to a string.
2752 std::string typeName;
2754 llvm::raw_string_ostream typeNameStr(typeName);
2755 Impl subPrinter(typeNameStr, state);
2756 DialectAsmPrinter printer(subPrinter);
2757 dialect.printType(type, printer);
2759 printDialectSymbol(os, "!
", dialect.getNamespace(), typeName);
2762 void AsmPrinter::Impl::printEscapedString(StringRef str) {
2764 llvm::printEscapedString(str, os);
2769 os <<
"\"0x" << llvm::toHex(str) <<
"\"";
2772 printHexString(StringRef(data.data(), data.size()));
2776 return state.pushCyclicPrinting(opaquePointer);
2792 assert(
impl &&
"expected AsmPrinter::getStream to be overriden");
2793 return impl->getStream();
2798 assert(
impl &&
"expected AsmPrinter::printFloat to be overriden");
2803 assert(
impl &&
"expected AsmPrinter::printType to be overriden");
2804 impl->printType(type);
2808 assert(
impl &&
"expected AsmPrinter::printAttribute to be overriden");
2809 impl->printAttribute(attr);
2813 assert(
impl &&
"expected AsmPrinter::printAlias to be overriden");
2814 return impl->printAlias(attr);
2818 assert(
impl &&
"expected AsmPrinter::printAlias to be overriden");
2819 return impl->printAlias(type);
2824 "expected AsmPrinter::printAttributeWithoutType to be overriden");
2829 assert(
impl &&
"expected AsmPrinter::printKeywordOrString to be overriden");
2834 assert(
impl &&
"expected AsmPrinter::printString to be overriden");
2836 printEscapedString(keyword,
getStream());
2841 assert(
impl &&
"expected AsmPrinter::printSymbolName to be overriden");
2846 assert(
impl &&
"expected AsmPrinter::printResourceHandle to be overriden");
2847 impl->printResourceHandle(resource);
2855 return impl->pushCyclicPrinting(opaquePointer);
2866 printAffineExprInternal(expr, BindingStrength::Weak, printValueName);
2872 const char *binopSpelling =
nullptr;
2875 unsigned pos = cast<AffineSymbolExpr>(expr).getPosition();
2877 printValueName(pos,
true);
2883 unsigned pos = cast<AffineDimExpr>(expr).getPosition();
2885 printValueName(pos,
false);
2891 os << cast<AffineConstantExpr>(expr).getValue();
2894 binopSpelling =
" + ";
2897 binopSpelling =
" * ";
2900 binopSpelling =
" floordiv ";
2903 binopSpelling =
" ceildiv ";
2906 binopSpelling =
" mod ";
2910 auto binOp = cast<AffineBinaryOpExpr>(expr);
2916 if (enclosingTightness == BindingStrength::Strong)
2920 auto rhsConst = dyn_cast<AffineConstantExpr>(rhsExpr);
2922 rhsConst.getValue() == -1) {
2924 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
2925 if (enclosingTightness == BindingStrength::Strong)
2930 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
2932 os << binopSpelling;
2933 printAffineExprInternal(rhsExpr, BindingStrength::Strong, printValueName);
2935 if (enclosingTightness == BindingStrength::Strong)
2941 if (enclosingTightness == BindingStrength::Strong)
2946 if (
auto rhs = dyn_cast<AffineBinaryOpExpr>(rhsExpr)) {
2949 if (
auto rrhs = dyn_cast<AffineConstantExpr>(rrhsExpr)) {
2950 if (rrhs.getValue() == -1) {
2951 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
2955 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
2958 printAffineExprInternal(rhs.getLHS(), BindingStrength::Weak,
2962 if (enclosingTightness == BindingStrength::Strong)
2967 if (rrhs.getValue() < -1) {
2968 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
2971 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
2973 os <<
" * " << -rrhs.getValue();
2974 if (enclosingTightness == BindingStrength::Strong)
2983 if (
auto rhsConst = dyn_cast<AffineConstantExpr>(rhsExpr)) {
2984 if (rhsConst.getValue() < 0) {
2985 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
2986 os <<
" - " << -rhsConst.getValue();
2987 if (enclosingTightness == BindingStrength::Strong)
2993 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
2996 printAffineExprInternal(rhsExpr, BindingStrength::Weak, printValueName);
2998 if (enclosingTightness == BindingStrength::Strong)
3003 printAffineExprInternal(expr, BindingStrength::Weak);
3004 isEq ? os <<
" == 0" : os <<
" >= 0";
3010 for (
int i = 0; i < (int)map.
getNumDims() - 1; ++i)
3011 os <<
'd' << i <<
", ";
3020 os <<
's' << i <<
", ";
3029 [&](
AffineExpr expr) { printAffineExpr(expr); });
3036 for (
unsigned i = 1; i < set.
getNumDims(); ++i)
3037 os <<
'd' << i - 1 <<
", ";
3046 os <<
's' << i <<
", ";
3055 for (
int i = 1; i < numConstraints; ++i) {
3059 if (numConstraints >= 1)
3060 printAffineConstraint(set.
getConstraint(numConstraints - 1),
3061 set.
isEq(numConstraints - 1));
3076 explicit OperationPrinter(raw_ostream &os,
AsmStateImpl &state)
3080 void printTopLevelOperation(
Operation *op);
3084 void printFullOpWithIndentAndLoc(
Operation *op);
3090 void printCustomOrGenericOp(
Operation *op)
override;
3092 void printGenericOp(
Operation *op,
bool printOpName)
override;
3095 void printBlockName(
Block *block);
3100 void print(
Block *block,
bool printBlockArgs =
true,
3101 bool printBlockTerminator =
true);
3104 void printValueID(
Value value,
bool printResultNo =
true,
3105 raw_ostream *streamOverride =
nullptr)
const;
3109 raw_ostream *streamOverride =
nullptr)
const;
3117 void printOptionalLocationSpecifier(
Location loc)
override {
3118 printTrailingLocation(loc);
3125 os.indent(currentIndent);
3129 void increaseIndent()
override { currentIndent += indentWidth; }
3132 void decreaseIndent()
override { currentIndent -= indentWidth; }
3141 bool omitType =
false)
override;
3144 void printOperand(
Value value)
override { printValueID(value); }
3145 void printOperand(
Value value, raw_ostream &os)
override {
3146 printValueID(value,
true, &os);
3154 void printOptionalAttrDictWithKeyword(
3162 void printSuccessor(
Block *successor)
override;
3166 void printSuccessorAndUseList(
Block *successor,
3171 bool printBlockTerminators,
bool printEmptyBlock)
override;
3178 state.getSSANameState().shadowRegionArgs(region, namesToUse);
3183 void printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3198 void printValueUsers(
Value value);
3202 void printUserIDs(
Operation *user,
bool prefixComma =
false);
3210 using PrintFn =
function_ref<void(StringRef, ValueFn)>;
3212 ResourceBuilder(PrintFn printFn) : printFn(printFn) {}
3213 ~ResourceBuilder()
override =
default;
3215 void buildBool(StringRef key,
bool data)
final {
3216 printFn(key, [&](raw_ostream &os) { os << (data ?
"true" :
"false"); });
3219 void buildString(StringRef key, StringRef data)
final {
3220 printFn(key, [&](raw_ostream &os) {
3222 llvm::printEscapedString(data, os);
3228 uint32_t dataAlignment)
final {
3229 printFn(key, [&](raw_ostream &os) {
3231 llvm::support::ulittle32_t dataAlignmentLE(dataAlignment);
3233 << llvm::toHex(StringRef(
reinterpret_cast<char *
>(&dataAlignmentLE),
3234 sizeof(dataAlignment)))
3235 << llvm::toHex(StringRef(data.data(), data.size())) <<
"\"";
3244 void printFileMetadataDictionary(
Operation *op);
3250 void printResourceFileMetadata(
function_ref<
void()> checkAddMetadataDict,
3261 const static unsigned indentWidth = 2;
3264 unsigned currentIndent = 0;
3268 void OperationPrinter::printTopLevelOperation(
Operation *op) {
3270 state.getAliasState().printNonDeferredAliases(*
this, newLine);
3273 printFullOpWithIndentAndLoc(op);
3277 state.getAliasState().printDeferredAliases(*
this, newLine);
3280 printFileMetadataDictionary(op);
3283 void OperationPrinter::printFileMetadataDictionary(
Operation *op) {
3284 bool sawMetadataEntry =
false;
3285 auto checkAddMetadataDict = [&] {
3286 if (!std::exchange(sawMetadataEntry,
true))
3287 os << newLine <<
"{-#" << newLine;
3291 printResourceFileMetadata(checkAddMetadataDict, op);
3294 if (sawMetadataEntry)
3295 os << newLine <<
"#-}" << newLine;
3298 void OperationPrinter::printResourceFileMetadata(
3301 bool hadResource =
false;
3302 bool needResourceComma =
false;
3303 bool needEntryComma =
false;
3304 auto processProvider = [&](StringRef dictName, StringRef name,
auto &provider,
3305 auto &&...providerArgs) {
3306 bool hadEntry =
false;
3307 auto printFn = [&](StringRef key, ResourceBuilder::ValueFn valueFn) {
3308 checkAddMetadataDict();
3310 auto printFormatting = [&]() {
3312 if (!std::exchange(hadResource,
true)) {
3313 if (needResourceComma)
3314 os <<
"," << newLine;
3315 os <<
" " << dictName <<
"_resources: {" << newLine;
3318 if (!std::exchange(hadEntry,
true)) {
3320 os <<
"," << newLine;
3321 os <<
" " << name <<
": {" << newLine;
3323 os <<
"," << newLine;
3327 std::optional<uint64_t> charLimit =
3329 if (charLimit.has_value()) {
3330 std::string resourceStr;
3331 llvm::raw_string_ostream ss(resourceStr);
3335 if (resourceStr.size() > charLimit.value())
3339 os <<
" " << key <<
": " << resourceStr;
3342 os <<
" " << key <<
": ";
3346 ResourceBuilder entryBuilder(printFn);
3347 provider.buildResources(op, providerArgs..., entryBuilder);
3349 needEntryComma |= hadEntry;
3351 os << newLine <<
" }";
3357 auto &dialectResources = state.getDialectResources();
3358 StringRef name = interface.getDialect()->getNamespace();
3359 auto it = dialectResources.find(interface.getDialect());
3360 if (it != dialectResources.end())
3361 processProvider(
"dialect", name, interface, it->second);
3363 processProvider(
"dialect", name, interface,
3367 os << newLine <<
" }";
3371 needEntryComma =
false;
3372 needResourceComma = hadResource;
3373 hadResource =
false;
3374 for (
const auto &printer : state.getResourcePrinters())
3375 processProvider(
"external", printer.getName(), printer);
3377 os << newLine <<
" }";
3385 void OperationPrinter::printRegionArgument(
BlockArgument arg,
3393 printOptionalAttrDict(argAttrs);
3395 printTrailingLocation(arg.
getLoc(),
false);
3398 void OperationPrinter::printFullOpWithIndentAndLoc(
Operation *op) {
3400 state.registerOperationLocation(op, newLine.curLine, currentIndent);
3402 os.indent(currentIndent);
3404 printTrailingLocation(op->
getLoc());
3406 printUsersComment(op);
3409 void OperationPrinter::printFullOp(
Operation *op) {
3411 auto printResultGroup = [&](
size_t resultNo,
size_t resultCount) {
3412 printValueID(op->
getResult(resultNo),
false);
3413 if (resultCount > 1)
3414 os <<
':' << resultCount;
3418 ArrayRef<int> resultGroups = state.getSSANameState().getOpResultGroups(op);
3419 if (!resultGroups.empty()) {
3422 interleaveComma(llvm::seq<int>(0, resultGroups.size() - 1), [&](
int i) {
3423 printResultGroup(resultGroups[i],
3424 resultGroups[i + 1] - resultGroups[i]);
3427 printResultGroup(resultGroups.back(), numResults - resultGroups.back());
3430 printResultGroup(0, numResults);
3436 printCustomOrGenericOp(op);
3439 void OperationPrinter::printUsersComment(
Operation *op) {
3443 printOperationID(op);
3444 }
else if (numResults && op->
use_empty()) {
3446 }
else if (numResults && !op->
use_empty()) {
3449 unsigned usedInNResults = 0;
3450 unsigned usedInNOperations = 0;
3453 if (userSet.insert(user).second) {
3454 ++usedInNOperations;
3455 usedInNResults += user->getNumResults();
3460 bool exactlyOneUniqueUse =
3461 usedInNResults <= 1 && usedInNOperations <= 1 && numResults == 1;
3462 os <<
" // " << (exactlyOneUniqueUse ?
"user" :
"users") <<
": ";
3463 bool shouldPrintBrackets = numResults > 1;
3464 auto printOpResult = [&](
OpResult opResult) {
3465 if (shouldPrintBrackets)
3467 printValueUsers(opResult);
3468 if (shouldPrintBrackets)
3472 interleaveComma(op->
getResults(), printOpResult);
3476 void OperationPrinter::printUsersComment(
BlockArgument arg) {
3482 os <<
" is used by ";
3483 printValueUsers(arg);
3488 void OperationPrinter::printValueUsers(
Value value) {
3496 if (userSet.insert(user).second)
3497 printUserIDs(user, index);
3501 void OperationPrinter::printUserIDs(
Operation *user,
bool prefixComma) {
3506 printOperationID(user);
3509 [
this](
Value result) { printValueID(result); });
3513 void OperationPrinter::printCustomOrGenericOp(
Operation *op) {
3519 opInfo->printAssembly(op, *
this, defaultDialectStack.back());
3524 if (
auto opPrinter = dialect->getOperationPrinter(op)) {
3529 if (name.count(
'.') == 1)
3530 name.consume_front((defaultDialectStack.back() +
".").str());
3534 opPrinter(op, *
this);
3541 printGenericOp(op,
true);
3544 void OperationPrinter::printGenericOp(
Operation *op,
bool printOpName) {
3548 interleaveComma(op->
getOperands(), [&](
Value value) { printValueID(value); });
3555 [&](
Block *successor) { printBlockName(successor); });
3567 if (op->getNumRegions() != 0) {
3569 interleaveComma(op->getRegions(), [&](Region ®ion) {
3570 printRegion(region, /*printEntryBlockArgs=*/true,
3571 /*printBlockTerminators=*/true, /*printEmptyBlock=*/true);
3576 printOptionalAttrDict(op->getPropertiesStorage()
3577 ? llvm::to_vector(op->getDiscardableAttrs())
3580 // Print the type signature of the operation.
3582 printFunctionalType(op);
3585 void OperationPrinter::printBlockName(Block *block) {
3586 os << state.getSSANameState().getBlockInfo(block).name;
3589 void OperationPrinter::print(Block *block, bool printBlockArgs,
3590 bool printBlockTerminator) {
3591 // Print the block label and argument list if requested.
3592 if (printBlockArgs) {
3593 os.indent(currentIndent);
3594 printBlockName(block);
3596 // Print the argument list if non-empty.
3597 if (!block->args_empty()) {
3599 interleaveComma(block->getArguments(), [&](BlockArgument arg) {
3602 printType(arg.getType());
3603 // TODO: We should allow location aliases on block arguments.
3604 printTrailingLocation(arg.getLoc(), /*allowAlias*/ false);
3610 // Print out some context information about the predecessors of this block.
3611 if (!block->getParent()) {
3612 os << " // block is not in a region!";
3613 } else if (block->hasNoPredecessors()) {
3614 if (!block->isEntryBlock())
3615 os << " // no predecessors";
3616 } else if (auto *pred = block->getSinglePredecessor()) {
3618 printBlockName(pred);
3620 // We want to print the predecessors in a stable order, not in
3621 // whatever order the use-list is in, so gather and sort them.
3622 SmallVector<BlockInfo, 4> predIDs;
3623 for (auto *pred : block->getPredecessors())
3624 predIDs.push_back(state.getSSANameState().getBlockInfo(pred));
3625 llvm::sort(predIDs, [](BlockInfo lhs, BlockInfo rhs) {
3626 return lhs.ordering < rhs.ordering;
3629 os << " // " << predIDs.size() << " preds: ";
3631 interleaveComma(predIDs, [&](BlockInfo pred) { os << pred.name; });
3636 currentIndent += indentWidth;
3638 if (printerFlags.shouldPrintValueUsers()) {
3639 for (BlockArgument arg : block->getArguments()) {
3640 os.indent(currentIndent);
3641 printUsersComment(arg);
3645 bool hasTerminator =
3646 !block->empty() && block->back().hasTrait<OpTrait::IsTerminator>();
3647 auto range = llvm::make_range(
3649 std::prev(block->end(),
3650 (!hasTerminator || printBlockTerminator) ? 0 : 1));
3651 for (auto &op : range) {
3652 printFullOpWithIndentAndLoc(&op);
3655 currentIndent -= indentWidth;
3658 void OperationPrinter::printValueID(Value value, bool printResultNo,
3659 raw_ostream *streamOverride) const {
3660 state.getSSANameState().printValueID(value, printResultNo,
3661 streamOverride ? *streamOverride : os);
3664 void OperationPrinter::printOperationID(Operation *op,
3665 raw_ostream *streamOverride) const {
3666 state.getSSANameState().printOperationID(op, streamOverride ? *streamOverride
3670 void OperationPrinter::printSuccessor(Block *successor) {
3671 printBlockName(successor);
3674 void OperationPrinter::printSuccessorAndUseList(Block *successor,
3675 ValueRange succOperands) {
3676 printBlockName(successor);
3677 if (succOperands.empty())
3681 interleaveComma(succOperands,
3682 [this](Value operand) { printValueID(operand); });
3684 interleaveComma(succOperands,
3685 [this](Value operand) { printType(operand.getType()); });
3689 void OperationPrinter::printRegion(Region ®ion, bool printEntryBlockArgs,
3690 bool printBlockTerminators,
3691 bool printEmptyBlock) {
3692 if (printerFlags.shouldSkipRegions()) {
3696 os << "{" << newLine;
3697 if (!region.empty()) {
3698 auto restoreDefaultDialect =
3699 llvm::make_scope_exit([&]() { defaultDialectStack.pop_back(); });
3700 if (auto iface = dyn_cast<OpAsmOpInterface>(region.getParentOp()))
3701 defaultDialectStack.push_back(iface.getDefaultDialect());
3703 defaultDialectStack.push_back("");
3705 auto *entryBlock = ®ion.front();
3706 // Force printing the block header if printEmptyBlock is set and the block
3707 // is empty or if printEntryBlockArgs is set and there are arguments to
3709 bool shouldAlwaysPrintBlockHeader =
3710 (printEmptyBlock && entryBlock->empty()) ||
3711 (printEntryBlockArgs && entryBlock->getNumArguments() != 0);
3712 print(entryBlock, shouldAlwaysPrintBlockHeader, printBlockTerminators);
3713 for (auto &b : llvm::drop_begin(region.getBlocks(), 1))
3716 os.indent(currentIndent) << "}";
3719 void OperationPrinter::printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3720 ValueRange operands) {
3722 os << "<<NULL AFFINE MAP>>";
3725 AffineMap map = mapAttr.getValue();
3726 unsigned numDims = map.getNumDims();
3727 auto printValueName = [&](unsigned pos, bool isSymbol) {
3728 unsigned index = isSymbol ? numDims + pos : pos;
3729 assert(index < operands.size());
3732 printValueID(operands[index]);
3737 interleaveComma(map.getResults(), [&](AffineExpr expr) {
3738 printAffineExpr(expr, printValueName);
3742 void OperationPrinter::printAffineExprOfSSAIds(AffineExpr expr,
3743 ValueRange dimOperands,
3744 ValueRange symOperands) {
3745 auto printValueName = [&](unsigned pos, bool isSymbol) {
3747 return printValueID(dimOperands[pos]);
3749 printValueID(symOperands[pos]);
3752 printAffineExpr(expr, printValueName);
3755 //===----------------------------------------------------------------------===//
3756 // print and dump methods
3757 //===----------------------------------------------------------------------===//
3759 void Attribute::print(raw_ostream &os, bool elideType) const {
3761 os << "<<NULL ATTRIBUTE>>";
3765 AsmState state(getContext());
3766 print(os, state, elideType);
3768 void Attribute::print(raw_ostream &os, AsmState &state, bool elideType) const {
3769 using AttrTypeElision = AsmPrinter::Impl::AttrTypeElision;
3770 AsmPrinter::Impl(os, state.getImpl())
3771 .printAttribute(*this, elideType ? AttrTypeElision::Must
3772 : AttrTypeElision::Never);
3775 void Attribute::dump() const {
3776 print(llvm::errs());
3777 llvm::errs() << "\n";
3780 void Attribute::printStripped(raw_ostream &os, AsmState &state) const {
3782 os << "<<NULL ATTRIBUTE>>";
3786 AsmPrinter::Impl subPrinter(os, state.getImpl());
3787 if (succeeded(subPrinter.printAlias(*this)))
3790 auto &dialect = this->getDialect();
3791 uint64_t posPrior = os.tell();
3792 DialectAsmPrinter printer(subPrinter);
3793 dialect.printAttribute(*this, printer);
3794 if (posPrior != os.tell())
3797 // Fallback to printing with prefix if the above failed to write anything
3798 // to the output stream.
3801 void Attribute::printStripped(raw_ostream &os) const {
3803 os << "<<NULL ATTRIBUTE>>";
3807 AsmState state(getContext());
3808 printStripped(os, state);
3811 void Type::print(raw_ostream &os) const {
3813 os << "<<NULL TYPE>>";
3817 AsmState state(getContext());
3820 void Type::print(raw_ostream &os, AsmState &state) const {
3821 AsmPrinter::Impl(os, state.getImpl()).printType(*this);
3824 void Type::dump() const {
3825 print(llvm::errs());
3826 llvm::errs() << "\n";
3829 void AffineMap::dump() const {
3830 print(llvm::errs());
3831 llvm::errs() << "\n";
3834 void IntegerSet::dump() const {
3835 print(llvm::errs());
3836 llvm::errs() << "\n";
3839 void AffineExpr::print(raw_ostream &os) const {
3841 os << "<<NULL AFFINE EXPR>>";
3844 AsmState state(getContext());
3845 AsmPrinter::Impl(os, state.getImpl()).printAffineExpr(*this);
3848 void AffineExpr::dump() const {
3849 print(llvm::errs());
3850 llvm::errs() << "\n";
3853 void AffineMap::print(raw_ostream &os) const {
3855 os << "<<NULL AFFINE MAP>>";
3858 AsmState state(getContext());
3859 AsmPrinter::Impl(os, state.getImpl()).printAffineMap(*this);
3862 void IntegerSet::print(raw_ostream &os) const {
3863 AsmState state(getContext());
3864 AsmPrinter::Impl(os, state.getImpl()).printIntegerSet(*this);
3867 void Value::print(raw_ostream &os) const { print(os, OpPrintingFlags()); }
3868 void Value::print(raw_ostream &os, const OpPrintingFlags &flags) const {
3870 os << "<<NULL VALUE>>";
3874 if (auto *op = getDefiningOp())
3875 return op->print(os, flags);
3876 // TODO: Improve BlockArgument print'ing.
3878 os <<
"<block argument> of type '" << arg.
getType()
3883 os <<
"<<NULL VALUE>>";
3887 if (
auto *op = getDefiningOp())
3888 return op->
print(os, state);
3892 os <<
"<block argument> of type '" << arg.
getType()
3897 print(llvm::errs());
3898 llvm::errs() <<
"\n";
3906 state.getImpl().getSSANameState().printValueID(*
this,
true,
3929 if (
auto result = llvm::dyn_cast<OpResult>(*
this)) {
3932 op = llvm::cast<BlockArgument>(*this).getOwner()->
getParentOp();
3934 os <<
"<<UNKNOWN SSA VALUE>>";
3940 printAsOperand(os, state);
3950 OperationPrinter printer(os, state.getImpl());
3951 if (!getParent() && !state.getPrinterFlags().shouldUseLocalScope()) {
3952 state.getImpl().initializeAliases(
this);
3953 printer.printTopLevelOperation(
this);
3955 printer.printFullOpWithIndentAndLoc(
this);
3961 llvm::errs() <<
"\n";
3967 os <<
"<<UNLINKED BLOCK>>\n";
3978 OperationPrinter(os, state.getImpl()).print(
this);
3987 os <<
"<<UNLINKED BLOCK>>\n";
3991 printAsOperand(os, state);
3994 OperationPrinter printer(os, state.getImpl());
3995 printer.printBlockName(
this);
4010 if (dimensions.empty())
4013 if (dimensions.empty())
4023 <<
"Failed parsing dimension list.";
4034 <<
"Failed parsing dimension list.";
4036 if (shapeArr.empty()) {
4038 <<
"Failed parsing dimension list. Did you mean an empty list? It "
4039 "must be denoted by \"[]\".";
static StringRef sanitizeIdentifier(StringRef name, SmallString< 16 > &buffer, StringRef allowedPunctChars="$._-", bool allowTrailingDigit=true)
Sanitize the given name such that it can be used as a valid identifier.
static void printSymbolReference(StringRef symbolRef, raw_ostream &os)
Print the given string as a symbol reference.
static void printFloatValue(const APFloat &apValue, raw_ostream &os, bool *printedHex=nullptr)
Print a floating point value in a way that the parser will be able to round-trip losslessly.
static llvm::ManagedStatic< AsmPrinterOptions > clOptions
static Operation * findParent(Operation *op, bool shouldUseLocalScope)
static void printKeywordOrString(StringRef keyword, raw_ostream &os)
Print the given string as a keyword, or a quoted and escaped string if it has any special or non-prin...
static bool isDialectSymbolSimpleEnoughForPrettyForm(StringRef symName)
Returns true if the given dialect symbol data is simple enough to print in the pretty form.
static void printDialectSymbol(raw_ostream &os, StringRef symPrefix, StringRef dialectName, StringRef symString)
Print the given dialect symbol to the stream.
static OpPrintingFlags verifyOpAndAdjustFlags(Operation *op, OpPrintingFlags printerFlags)
Verifies the operation and switches to generic op printing if verification fails.
MLIR_CRUNNERUTILS_EXPORT void printString(char const *s)
MLIR_CRUNNERUTILS_EXPORT void printNewline()
static void visit(Operation *op, DenseSet< Operation * > &visited)
Visits all the pdl.operand(s), pdl.result(s), and pdl.operation(s) connected to the given operation.
static MLIRContext * getContext(OpFoldResult val)
static std::string diag(const llvm::Value &value)
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
static void printRegion(llvm::raw_ostream &os, Region *region, OpPrintingFlags &flags)
Base type for affine expression.
AffineExprKind getKind() const
Return the classification for this type.
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
unsigned getNumSymbols() const
unsigned getNumDims() const
ArrayRef< AffineExpr > getResults() const
This class represents an opaque handle to a dialect resource entry.
Dialect * getDialect() const
Return the dialect that owns the resource.
This class represents a single parsed resource entry.
virtual FailureOr< AsmResourceBlob > parseAsBlob(BlobAllocatorFn allocator) const =0
Parse the resource entry represented by a binary blob.
virtual InFlightDiagnostic emitError() const =0
Emit an error at the location of this entry.
virtual AsmResourceEntryKind getKind() const =0
Return the kind of this value.
virtual FailureOr< std::string > parseAsString() const =0
Parse the resource entry represented by a human-readable string.
virtual FailureOr< bool > parseAsBool() const =0
Parse the resource entry represented by a boolean.
virtual StringRef getKey() const =0
Return the key of the resource entry.
MLIRContext * getContext() const
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
virtual ParseResult parseRSquare()=0
Parse a ] token.
virtual ParseResult parseDimensionList(SmallVectorImpl< int64_t > &dimensions, bool allowDynamic=true, bool withTrailingX=true)=0
Parse a dimension list of a tensor or memref type.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
ParseResult parseTypeList(SmallVectorImpl< Type > &result)
Parse a type list.
virtual ParseResult parseOptionalLSquare()=0
Parse a [ token if present.
Impl(raw_ostream &os, AsmStateImpl &state)
BindingStrength
This enum is used to represent the binding strength of the enclosing context that an AffineExprStorag...
void printHexString(StringRef str)
Print a hex string, wrapped with "".
void printDenseArrayAttr(DenseArrayAttr attr)
Print a dense array attribute.
void printDenseElementsAttr(DenseElementsAttr attr, bool allowHex)
Print a dense elements attribute.
void printAttribute(Attribute attr, AttrTypeElision typeElision=AttrTypeElision::Never)
Print the given attribute or an alias.
void printDimensionList(ArrayRef< int64_t > shape)
OpPrintingFlags printerFlags
A set of flags to control the printer's behavior.
raw_ostream & os
The output stream for the printer.
void printResourceHandle(const AsmDialectResourceHandle &resource)
Print a reference to the given resource that is owned by the given dialect.
raw_ostream & getStream()
Returns the output stream of the printer.
LogicalResult printAlias(Attribute attr)
Print the alias for the given attribute, return failure if no alias could be printed.
void printDialectAttribute(Attribute attr)
void interleaveComma(const Container &c, UnaryFunctor eachFn) const
void printDialectType(Type type)
void printLocation(LocationAttr loc, bool allowAlias=false)
Print the given location to the stream.
AsmStateImpl & state
An underlying assembly printer state.
void printAffineMap(AffineMap map)
void printTrailingLocation(Location loc, bool allowAlias=true)
void printAffineExprInternal(AffineExpr expr, BindingStrength enclosingTightness, function_ref< void(unsigned, bool)> printValueName=nullptr)
void printEscapedString(StringRef str)
Print an escaped string, wrapped with "".
void printAffineExpr(AffineExpr expr, function_ref< void(unsigned, bool)> printValueName=nullptr)
void printDenseStringElementsAttr(DenseStringElementsAttr attr)
Print a dense string elements attribute.
void printAttributeImpl(Attribute attr, AttrTypeElision typeElision=AttrTypeElision::Never)
Print the given attribute without considering an alias.
void printAffineConstraint(AffineExpr expr, bool isEq)
void printDenseIntOrFPElementsAttr(DenseIntOrFPElementsAttr attr, bool allowHex)
Print a dense elements attribute.
AttrTypeElision
This enum describes the different kinds of elision for the type of an attribute when printing it.
@ May
The type may be elided when it matches the default used in the parser (for example i64 is the default...
@ Never
The type must not be elided,.
@ Must
The type must be elided.
LogicalResult pushCyclicPrinting(const void *opaquePointer)
void printIntegerSet(IntegerSet set)
NewLineCounter newLine
A tracker for the number of new lines emitted during printing.
void printOptionalAttrDict(ArrayRef< NamedAttribute > attrs, ArrayRef< StringRef > elidedAttrs={}, bool withKeyword=false)
void printType(Type type)
Print the given type or an alias.
void printLocationInternal(LocationAttr loc, bool pretty=false, bool isTopLevel=false)
void printTypeImpl(Type type)
Print the given type.
void printNamedAttribute(NamedAttribute attr)
virtual void printAttributeWithoutType(Attribute attr)
Print the given attribute without its type.
virtual LogicalResult printAlias(Attribute attr)
Print the alias for the given attribute, return failure if no alias could be printed.
virtual void popCyclicPrinting()
Removes the element that was last inserted with a successful call to pushCyclicPrinting.
virtual LogicalResult pushCyclicPrinting(const void *opaquePointer)
Pushes a new attribute or type in the form of a type erased pointer into an internal set.
virtual void printType(Type type)
virtual void printKeywordOrString(StringRef keyword)
Print the given string as a keyword, or a quoted and escaped string if it has any special or non-prin...
virtual void printSymbolName(StringRef symbolRef)
Print the given string as a symbol reference, i.e.
virtual void printString(StringRef string)
Print the given string as a quoted string, escaping any special or non-printable characters in it.
virtual void printAttribute(Attribute attr)
void printDimensionList(ArrayRef< int64_t > shape)
virtual raw_ostream & getStream() const
Return the raw output stream used by this printer.
virtual void printResourceHandle(const AsmDialectResourceHandle &resource)
Print a handle to the given dialect resource.
virtual void printFloat(const APFloat &value)
Print the given floating point value in a stabilized form that can be roundtripped through the IR.
This class is used to build resource entries for use by the printer.
virtual void buildString(StringRef key, StringRef data)=0
Build a resource entry represented by the given human-readable string value.
virtual void buildBool(StringRef key, bool data)=0
Build a resource entry represented by the given bool.
virtual void buildBlob(StringRef key, ArrayRef< char > data, uint32_t dataAlignment)=0
Build an resource entry represented by the given binary blob data.
This class represents an instance of a resource parser.
static std::unique_ptr< AsmResourcePrinter > fromCallable(StringRef name, CallableT &&printFn)
Return a resource printer implemented via the given callable, whose form should match that of buildRe...
This class provides management for the lifetime of the state used when printing the IR.
void attachResourcePrinter(std::unique_ptr< AsmResourcePrinter > printer)
Attach the given resource printer to the AsmState.
DenseMap< Dialect *, SetVector< AsmDialectResourceHandle > > & getDialectResources() const
Returns a map of dialect resources that were referenced when using this state to print IR.
void attachFallbackResourcePrinter(FallbackAsmResourceMap &map)
Attach resource printers to the AsmState for the fallback resources in the given map.
const OpPrintingFlags & getPrinterFlags() const
Get the printer flags.
Attributes are known-constant values of operations.
Dialect & getDialect() const
Get the dialect this attribute is registered to.
bool hasTrait()
Returns true if the type was registered with a particular trait.
const void * getAsOpaquePointer() const
Get an opaque pointer to the attribute.
static Attribute getFromOpaquePointer(const void *ptr)
Construct an attribute from the opaque pointer representation.
This class represents an argument of a Block.
Location getLoc() const
Return the location for this argument.
unsigned getArgNumber() const
Returns the number of this argument.
Block represents an ordered list of Operations.
void printAsOperand(raw_ostream &os, bool printType=true)
Print out the name of the block without printing its body.
void print(raw_ostream &os)
BlockArgListType getArguments()
bool isEntryBlock()
Return if this block is the entry block in the parent region.
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
An attribute that represents a reference to a dense vector or tensor object.
This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine.
~DialectAsmParser() override
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
~DialectAsmPrinter() override
A collection of dialect interfaces within a context, for a given concrete interface type.
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
virtual void printAttribute(Attribute, DialectAsmPrinter &) const
Print an attribute registered to this dialect.
virtual void printType(Type, DialectAsmPrinter &) const
Print a type registered to this dialect.
An attribute that associates a referenced attribute with a unique identifier.
A fallback map containing external resources not explicitly handled by another parser/printer.
std::vector< std::unique_ptr< AsmResourcePrinter > > getPrinters()
Build a set of resource printers to print the resources within this map.
An integer set representing a conjunction of one or more affine equalities and inequalities.
unsigned getNumDims() const
unsigned getNumConstraints() const
AffineExpr getConstraint(unsigned idx) const
bool isEq(unsigned idx) const
Returns true if the idx^th constraint is an equality, false if it is an inequality.
unsigned getNumSymbols() const
Location objects represent source locations information in MLIR.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
NamedAttribute represents a combination of a name and an Attribute value.
Attribute getValue() const
Return the value of the attribute.
virtual std::string getResourceKey(const AsmDialectResourceHandle &handle) const
Return a key to use for the given resource.
virtual LogicalResult parseResource(AsmParsedResourceEntry &entry) const
Hook for parsing resource entries.
AliasResult
Holds the result of getAlias hook call.
@ FinalAlias
An alias was provided and it should be used (no other hooks will be checked).
@ NoAlias
The object (type or attribute) is not supported by the hook and an alias was not provided.
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
void printFunctionalType(Operation *op)
Print the complete type of an operation in functional form.
Set of flags used to control the behavior of the various IR print methods (e.g.
bool shouldElideElementsAttr(ElementsAttr attr) const
Return if the given ElementsAttr should be elided.
std::optional< int64_t > getLargeElementsAttrLimit() const
Return the size limit for printing large ElementsAttr.
bool shouldAssumeVerified() const
Return if operation verification should be skipped.
OpPrintingFlags & printValueUsers()
Print users of values as comments.
OpPrintingFlags & printLargeElementsAttrWithHex(int64_t largeElementLimit=100)
Enables the printing of large element attributes with a hex string.
bool shouldUseLocalScope() const
Return if the printer should use local scope when dumping the IR.
bool shouldPrintDebugInfoPrettyForm() const
Return if debug information should be printed in the pretty form.
bool shouldPrintElementsAttrWithHex(ElementsAttr attr) const
Return if the given ElementsAttr should be printed as hex string.
bool shouldPrintUniqueSSAIDs() const
Return if printer should use unique SSA IDs.
bool shouldPrintValueUsers() const
Return if the printer should print users of values.
int64_t getLargeElementsAttrHexLimit() const
Return the size limit for printing large ElementsAttr as hex string.
bool shouldPrintGenericOpForm() const
Return if operations should be printed in the generic form.
OpPrintingFlags & elideLargeResourceString(int64_t largeResourceLimit=64)
Enables the elision of large resources strings by omitting them from the dialect_resources section.
bool shouldPrintDebugInfo() const
Return if debug information should be printed.
OpPrintingFlags & elideLargeElementsAttrs(int64_t largeElementLimit=16)
Enables the elision of large elements attributes by printing a lexically valid but otherwise meaningl...
OpPrintingFlags & enableDebugInfo(bool enable=true, bool prettyForm=false)
Enable or disable printing of debug information (based on enable).
OpPrintingFlags()
Initialize the printing flags with default supplied by the cl::opts above.
bool shouldSkipRegions() const
Return if regions should be skipped.
OpPrintingFlags & printGenericOpForm(bool enable=true)
Always print operations in the generic form.
OpPrintingFlags & assumeVerified()
Do not verify the operation when using custom operation printers.
std::optional< uint64_t > getLargeResourceStringLimit() const
Return the size limit in chars for printing large resources.
OpPrintingFlags & useLocalScope()
Use local scope when printing the operation.
OpPrintingFlags & skipRegions(bool skip=true)
Skip printing regions.
This is a value defined by a result of an operation.
Operation * getOwner() const
Returns the operation that owns this result.
unsigned getResultNumber() const
Returns the number of this result.
This class provides the API for ops that are known to be isolated from above.
This class provides the API for ops that are known to be terminators.
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
void printAssembly(Operation *op, OpAsmPrinter &p, StringRef defaultDialect) const
This hook implements the AsmPrinter for this operation.
void print(raw_ostream &os) const
Operation is the basic unit of execution within MLIR.
bool use_empty()
Returns true if this operation has no uses.
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
Dialect * getDialect()
Return the dialect this operation is associated with, or nullptr if the associated dialect is not loa...
unsigned getNumSuccessors()
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
void print(raw_ostream &os, const OpPrintingFlags &flags=std::nullopt)
MLIRContext * getContext()
Return the context this operation is associated with.
std::optional< RegisteredOperationName > getRegisteredInfo()
If this operation has a registered operation description, return it.
Location getLoc()
The source location the operation was defined or derived from.
unsigned getNumOperands()
Attribute getPropertiesAsAttribute()
Return the properties converted to an attribute.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
ArrayRef< NamedAttribute > getAttrs()
Return all of the attributes on this operation.
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
OperationName getName()
The name of an operation is the key identifier for it.
operand_type_range getOperandTypes()
result_type_range getResultTypes()
operand_range getOperands()
Returns an iterator on the underlying Value's.
user_range getUsers()
Returns a range of all users.
SuccessorRange getSuccessors()
result_range getResults()
unsigned getNumResults()
Return the number of results held by this operation.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
iterator_range< OpIterator > getOps()
Operation * getParentOp()
Return the parent operation this region is attached to.
unsigned getNumArguments()
BlockArgument getArgument(unsigned i)
This diagnostic handler is a simple RAII class that registers and erases a diagnostic handler on a gi...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
const void * getAsOpaquePointer() const
Methods for supporting PointerLikeTypeTraits.
Dialect & getDialect() const
Get the dialect this type is registered to.
static Type getFromOpaquePointer(const void *pointer)
bool hasTrait()
Returns true if the type was registered with a particular trait.
void walkImmediateSubElements(function_ref< void(Attribute)> walkAttrsFn, function_ref< void(Type)> walkTypesFn) const
Walk all of the immediately nested sub-attributes and sub-types.
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
bool use_empty() const
Returns true if this value has no uses.
void print(raw_ostream &os) const
Type getType() const
Return the type of this value.
void printAsOperand(raw_ostream &os, AsmState &state) const
Print this value as if it were an operand.
user_range getUsers() const
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
void registerOperationLocation(Operation *op, unsigned line, unsigned col)
Register the location, line and column, within the buffer that the given operation was printed at.
const OpPrintingFlags & getPrinterFlags() const
Get the printer flags.
auto getResourcePrinters()
Return the non-dialect resource printers.
LogicalResult pushCyclicPrinting(const void *opaquePointer)
SSANameState & getSSANameState()
Get the state used for SSA names.
DialectInterfaceCollection< OpAsmDialectInterface > & getDialectInterfaces()
Return the dialects within the context that implement OpAsmDialectInterface.
AliasState & getAliasState()
Get the state used for aliases.
void initializeAliases(Operation *op)
Initialize the alias state to enable the printing of aliases.
AsmStateImpl(Operation *op, const OpPrintingFlags &printerFlags, AsmState::LocationMap *locationMap)
DenseMap< Dialect *, SetVector< AsmDialectResourceHandle > > & getDialectResources()
Return the referenced dialect resources within the printer.
AsmStateImpl(MLIRContext *ctx, const OpPrintingFlags &printerFlags, AsmState::LocationMap *locationMap)
DistinctState & getDistinctState()
Get the state used for distinct attribute identifiers.
Base class for DenseArrayAttr that is instantiated and specialized for each supported element type be...
static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef< T > content)
Builder from ArrayRef<T>.
void printType(Type type, AsmPrinter &printer)
Prints an LLVM Dialect type.
LogicalResult parseCommaSeparatedList(llvm::cl::Option &opt, StringRef argName, StringRef optionStr, function_ref< LogicalResult(StringRef)> elementParseFn)
Parse a string containing a list of comma-delimited elements, invoking the given parser for each sub-...
void printDimensionList(raw_ostream &stream, Range &&shape)
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
bool operator<(const Fraction &x, const Fraction &y)
Include the generated interface declarations.
ParseResult parseDimensionList(OpAsmParser &parser, DenseI64ArrayAttr &dimensions)
StringRef toString(AsmResourceEntryKind kind)
@ CeilDiv
RHS of ceildiv is always a constant or a symbolic expression.
@ Mul
RHS of mul is always a constant or a symbolic expression.
@ Mod
RHS of mod is always a constant or a symbolic expression with a positive value.
@ DimId
Dimensional identifier.
@ FloorDiv
RHS of floordiv is always a constant or a symbolic expression.
@ Constant
Constant integer.
@ SymbolId
Symbolic identifier.
void registerAsmPrinterCLOptions()
Register a set of useful command-line options that can be used to configure various flags within the ...
Type parseType(llvm::StringRef typeStr, MLIRContext *context, size_t *numRead=nullptr, bool isKnownNullTerminated=false)
This parses a single MLIR type to an MLIR context if it was valid.
AsmResourceEntryKind
This enum represents the different kinds of resource values.
@ Blob
A blob of data with an accompanying alignment.
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
raw_ostream & operator<<(raw_ostream &os, const AliasResult &result)
Represents a range (offset, size, and stride) where each element of the triple may be dynamic or stat...
This trait is used to determine if a storage user, like Type, is mutable or not.