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"
80 [&]() {
return parseType(result.emplace_back()); });
96 auto &os = getStream();
100 *this << (operand ? operand.getType() : Type());
116 *this << (result ? result.getType() : Type());
128 #include "mlir/IR/OpAsmInterface.cpp.inc"
132 return entry.
emitError() <<
"unknown 'resource' key '" << entry.
getKey()
133 <<
"' for dialect '" << getDialect()->getNamespace()
145 struct AsmPrinterOptions {
146 llvm::cl::opt<int64_t> printElementsAttrWithHexIfLarger{
147 "mlir-print-elementsattrs-with-hex-if-larger",
149 "Print DenseElementsAttrs with a hex string that have "
150 "more elements than the given upper limit (use -1 to disable)")};
152 llvm::cl::opt<unsigned> elideElementsAttrIfLarger{
153 "mlir-elide-elementsattrs-if-larger",
154 llvm::cl::desc(
"Elide ElementsAttrs with \"...\" that have "
155 "more elements than the given upper limit")};
157 llvm::cl::opt<unsigned> elideResourceStringsIfLarger{
158 "mlir-elide-resource-strings-if-larger",
160 "Elide printing value of resources if string is too long in chars.")};
162 llvm::cl::opt<bool> printDebugInfoOpt{
163 "mlir-print-debuginfo", llvm::cl::init(
false),
164 llvm::cl::desc(
"Print debug info in MLIR output")};
166 llvm::cl::opt<bool> printPrettyDebugInfoOpt{
167 "mlir-pretty-debuginfo", llvm::cl::init(
false),
168 llvm::cl::desc(
"Print pretty debug info in MLIR output")};
172 llvm::cl::opt<bool> printGenericOpFormOpt{
173 "mlir-print-op-generic", llvm::cl::init(
false),
174 llvm::cl::desc(
"Print the generic op form"), llvm::cl::Hidden};
176 llvm::cl::opt<bool> assumeVerifiedOpt{
177 "mlir-print-assume-verified", llvm::cl::init(
false),
178 llvm::cl::desc(
"Skip op verification when using custom printers"),
181 llvm::cl::opt<bool> printLocalScopeOpt{
182 "mlir-print-local-scope", llvm::cl::init(
false),
183 llvm::cl::desc(
"Print with local scope and inline information (eliding "
184 "aliases for attributes, types, and locations")};
186 llvm::cl::opt<bool> skipRegionsOpt{
187 "mlir-print-skip-regions", llvm::cl::init(
false),
188 llvm::cl::desc(
"Skip regions when printing ops.")};
190 llvm::cl::opt<bool> printValueUsers{
191 "mlir-print-value-users", llvm::cl::init(
false),
193 "Print users of operation results and block arguments as a comment")};
195 llvm::cl::opt<bool> printUniqueSSAIDs{
196 "mlir-print-unique-ssa-ids", llvm::cl::init(
false),
197 llvm::cl::desc(
"Print unique SSA ID numbers for values, block arguments "
198 "and naming conflicts across all regions")};
200 llvm::cl::opt<bool> useNameLocAsPrefix{
201 "mlir-use-nameloc-as-prefix", llvm::cl::init(
false),
202 llvm::cl::desc(
"Print SSA IDs using NameLocs as prefixes")};
206 static llvm::ManagedStatic<AsmPrinterOptions>
clOptions;
217 : printDebugInfoFlag(false), printDebugInfoPrettyFormFlag(false),
218 printGenericOpFormFlag(false), skipRegionsFlag(false),
219 assumeVerifiedFlag(false), printLocalScope(false),
220 printValueUsersFlag(false), printUniqueSSAIDsFlag(false),
221 useNameLocAsPrefix(false) {
225 if (
clOptions->elideElementsAttrIfLarger.getNumOccurrences())
226 elementsAttrElementLimit =
clOptions->elideElementsAttrIfLarger;
227 if (
clOptions->printElementsAttrWithHexIfLarger.getNumOccurrences())
228 elementsAttrHexElementLimit =
229 clOptions->printElementsAttrWithHexIfLarger.getValue();
230 if (
clOptions->elideResourceStringsIfLarger.getNumOccurrences())
231 resourceStringCharLimit =
clOptions->elideResourceStringsIfLarger;
232 printDebugInfoFlag =
clOptions->printDebugInfoOpt;
233 printDebugInfoPrettyFormFlag =
clOptions->printPrettyDebugInfoOpt;
234 printGenericOpFormFlag =
clOptions->printGenericOpFormOpt;
235 assumeVerifiedFlag =
clOptions->assumeVerifiedOpt;
236 printLocalScope =
clOptions->printLocalScopeOpt;
237 skipRegionsFlag =
clOptions->skipRegionsOpt;
238 printValueUsersFlag =
clOptions->printValueUsers;
239 printUniqueSSAIDsFlag =
clOptions->printUniqueSSAIDs;
240 useNameLocAsPrefix =
clOptions->useNameLocAsPrefix;
249 elementsAttrElementLimit = largeElementLimit;
255 elementsAttrHexElementLimit = largeElementLimit;
261 resourceStringCharLimit = largeResourceLimit;
269 printDebugInfoFlag = enable;
270 printDebugInfoPrettyFormFlag = prettyForm;
276 printGenericOpFormFlag = enable;
282 skipRegionsFlag = skip;
288 assumeVerifiedFlag =
true;
296 printLocalScope =
true;
302 printValueUsersFlag =
true;
308 return elementsAttrElementLimit &&
309 *elementsAttrElementLimit < int64_t(attr.getNumElements()) &&
310 !llvm::isa<SplatElementsAttr>(attr);
316 return (elementsAttrHexElementLimit != -1) &&
317 (elementsAttrHexElementLimit < int64_t(attr.getNumElements())) &&
318 !llvm::isa<SplatElementsAttr>(attr);
323 return elementsAttrElementLimit;
328 return elementsAttrHexElementLimit;
333 return resourceStringCharLimit;
338 return printDebugInfoFlag;
343 return printDebugInfoPrettyFormFlag;
348 return printGenericOpFormFlag;
356 return assumeVerifiedFlag;
364 return printValueUsersFlag;
374 return useNameLocAsPrefix;
385 struct NewLineCounter {
386 unsigned curLine = 1;
389 static raw_ostream &
operator<<(raw_ostream &os, NewLineCounter &newLine) {
408 template <
typename Container,
typename UnaryFunctor>
410 llvm::interleaveComma(c,
os, eachFn);
456 function_ref<
void(
unsigned,
bool)> printValueName =
nullptr);
469 bool withKeyword =
false);
473 bool isTopLevel =
false);
509 function_ref<
void(
unsigned,
bool)> printValueName =
nullptr);
533 SymbolAlias(StringRef name, uint32_t suffixIndex,
bool isType,
535 : name(name), suffixIndex(suffixIndex), isType(isType),
536 isDeferrable(isDeferrable) {}
539 void print(raw_ostream &os)
const {
540 os << (isType ?
"!" :
"#") << name;
546 bool isTypeAlias()
const {
return isType; }
549 bool canBeDeferred()
const {
return isDeferrable; }
555 uint32_t suffixIndex : 30;
559 bool isDeferrable : 1;
563 bool isPrinted =
false;
569 class AliasInitializer {
573 llvm::BumpPtrAllocator &aliasAllocator)
574 : interfaces(interfaces), aliasAllocator(aliasAllocator),
575 aliasOS(aliasBuffer) {}
578 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias);
586 std::pair<size_t, size_t>
visit(
Attribute attr,
bool canBeDeferred =
false,
587 bool elideType =
false) {
588 return visitImpl(attr, aliases, canBeDeferred, elideType);
595 std::pair<size_t, size_t>
visit(
Type type,
bool canBeDeferred =
false) {
596 return visitImpl(type, aliases, canBeDeferred);
600 struct InProgressAliasInfo {
601 InProgressAliasInfo()
602 : aliasDepth(0), isType(false), canBeDeferred(false) {}
603 InProgressAliasInfo(StringRef alias)
604 : alias(alias), aliasDepth(1), isType(false), canBeDeferred(false) {}
606 bool operator<(
const InProgressAliasInfo &rhs)
const {
608 if (aliasDepth != rhs.aliasDepth)
609 return aliasDepth < rhs.aliasDepth;
610 if (isType != rhs.isType)
612 return alias < rhs.alias;
617 std::optional<StringRef> alias;
620 unsigned aliasDepth : 30;
624 bool canBeDeferred : 1;
634 template <
typename T,
typename... PrintArgs>
635 std::pair<size_t, size_t>
637 llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
638 bool canBeDeferred, PrintArgs &&...printArgs);
641 void markAliasNonDeferrable(
size_t aliasIndex);
645 template <
typename T>
646 void generateAlias(T symbol, InProgressAliasInfo &alias,
bool canBeDeferred);
650 static void initializeAliases(
651 llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
652 llvm::MapVector<const void *, SymbolAlias> &symbolToAlias);
658 llvm::BumpPtrAllocator &aliasAllocator;
661 llvm::MapVector<const void *, InProgressAliasInfo> aliases;
665 llvm::raw_svector_ostream aliasOS;
673 class DummyAliasOperationPrinter :
private OpAsmPrinter {
675 explicit DummyAliasOperationPrinter(
const OpPrintingFlags &printerFlags,
676 AliasInitializer &initializer)
677 : printerFlags(printerFlags), initializer(initializer) {}
681 void printCustomOrGenericOp(
Operation *op)
override {
683 if (printerFlags.shouldPrintDebugInfo())
684 initializer.visit(op->
getLoc(),
true);
687 if (!printerFlags.shouldPrintGenericOpForm()) {
698 void printGenericOp(
Operation *op,
bool printOpName =
true)
override {
700 if (!printerFlags.shouldSkipRegions()) {
714 printAttribute(attr.getValue());
720 void print(
Block *block,
bool printBlockArgs =
true,
721 bool printBlockTerminator =
true) {
724 if (printBlockArgs) {
729 if (printerFlags.shouldPrintDebugInfo())
731 initializer.visit(arg.getLoc(),
false);
739 auto range = llvm::make_range(
741 std::prev(block->
end(),
742 (!hasTerminator || printBlockTerminator) ? 0 : 1));
744 printCustomOrGenericOp(&op);
749 bool printBlockTerminators,
750 bool printEmptyBlock =
false)
override {
753 if (printerFlags.shouldSkipRegions()) {
758 auto *entryBlock = ®ion.
front();
759 print(entryBlock, printEntryBlockArgs, printBlockTerminators);
760 for (
Block &b : llvm::drop_begin(region, 1))
765 bool omitType)
override {
768 if (printerFlags.shouldPrintDebugInfo())
770 initializer.visit(arg.
getLoc(),
false);
774 void printType(
Type type)
override { initializer.visit(type); }
777 void printAttribute(
Attribute attr)
override { initializer.visit(attr); }
778 void printAttributeWithoutType(
Attribute attr)
override {
779 printAttribute(attr);
781 LogicalResult printAlias(
Attribute attr)
override {
782 initializer.visit(attr);
785 LogicalResult printAlias(
Type type)
override {
786 initializer.visit(type);
791 void printOptionalLocationSpecifier(
Location loc)
override {
801 if (elidedAttrs.empty()) {
803 printAttribute(attr.getValue());
806 llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
809 if (!elidedAttrsSet.contains(attr.getName().strref()))
810 printAttribute(attr.getValue());
812 void printOptionalAttrDictWithKeyword(
815 printOptionalAttrDict(attrs, elidedAttrs);
820 raw_ostream &getStream()
const override {
return os; }
824 void printFloat(
const APFloat &)
override {}
825 void printAffineMapOfSSAIds(AffineMapAttr,
ValueRange)
override {}
828 void increaseIndent()
override {}
829 void decreaseIndent()
override {}
830 void printOperand(
Value)
override {}
831 void printOperand(
Value, raw_ostream &os)
override {
840 void printSymbolName(StringRef)
override {}
841 void printSuccessor(
Block *)
override {}
849 AliasInitializer &initializer;
852 mutable llvm::raw_null_ostream os;
857 explicit DummyAliasDialectAsmPrinter(AliasInitializer &initializer,
860 : initializer(initializer), canBeDeferred(canBeDeferred),
861 childIndices(childIndices) {}
866 template <
typename T,
typename... PrintArgs>
867 size_t printAndVisitNestedAliases(T value, PrintArgs &&...printArgs) {
868 printAndVisitNestedAliasesImpl(value, printArgs...);
869 return maxAliasDepth;
875 void printAndVisitNestedAliasesImpl(
Attribute attr,
bool elideType) {
876 if (!isa<BuiltinDialect>(attr.
getDialect())) {
880 }
else if (llvm::isa<AffineMapAttr, DenseArrayAttr, FloatAttr, IntegerAttr,
881 IntegerSetAttr, UnitAttr>(attr)) {
883 }
else if (
auto distinctAttr = dyn_cast<DistinctAttr>(attr)) {
884 printAttribute(distinctAttr.getReferencedAttr());
885 }
else if (
auto dictAttr = dyn_cast<DictionaryAttr>(attr)) {
887 printAttribute(nestedAttr.getName());
888 printAttribute(nestedAttr.getValue());
890 }
else if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr)) {
891 for (
Attribute nestedAttr : arrayAttr.getValue())
892 printAttribute(nestedAttr);
893 }
else if (
auto typeAttr = dyn_cast<TypeAttr>(attr)) {
895 }
else if (
auto locAttr = dyn_cast<OpaqueLoc>(attr)) {
896 printAttribute(locAttr.getFallbackLocation());
897 }
else if (
auto locAttr = dyn_cast<NameLoc>(attr)) {
898 if (!isa<UnknownLoc>(locAttr.getChildLoc()))
899 printAttribute(locAttr.getChildLoc());
900 }
else if (
auto locAttr = dyn_cast<CallSiteLoc>(attr)) {
901 printAttribute(locAttr.getCallee());
902 printAttribute(locAttr.getCaller());
903 }
else if (
auto locAttr = dyn_cast<FusedLoc>(attr)) {
904 if (
Attribute metadata = locAttr.getMetadata())
905 printAttribute(metadata);
906 for (
Location nestedLoc : locAttr.getLocations())
907 printAttribute(nestedLoc);
912 if (
auto typedAttr = llvm::dyn_cast<TypedAttr>(attr)) {
913 Type attrType = typedAttr.getType();
914 if (!llvm::isa<NoneType>(attrType))
919 void printAndVisitNestedAliasesImpl(
Type type) {
924 if (
auto memrefTy = llvm::dyn_cast<MemRefType>(type)) {
926 MemRefLayoutAttrInterface layout = memrefTy.getLayout();
927 if (!llvm::isa<AffineMapAttr>(layout) || !layout.isIdentity())
928 printAttribute(memrefTy.getLayout());
929 if (memrefTy.getMemorySpace())
930 printAttribute(memrefTy.getMemorySpace());
935 auto visitFn = [&](
auto element) {
937 (void)printAlias(element);
944 recordAliasResult(initializer.visit(type, canBeDeferred));
948 void printAttribute(
Attribute attr)
override {
949 recordAliasResult(initializer.visit(attr, canBeDeferred));
951 void printAttributeWithoutType(
Attribute attr)
override {
953 initializer.visit(attr, canBeDeferred,
true));
955 LogicalResult printAlias(
Attribute attr)
override {
956 printAttribute(attr);
959 LogicalResult printAlias(
Type type)
override {
965 void recordAliasResult(std::pair<size_t, size_t> aliasDepthAndIndex) {
966 childIndices.push_back(aliasDepthAndIndex.second);
967 if (aliasDepthAndIndex.first > maxAliasDepth)
968 maxAliasDepth = aliasDepthAndIndex.first;
973 raw_ostream &getStream()
const override {
return os; }
977 void printFloat(
const APFloat &)
override {}
980 void printSymbolName(StringRef)
override {}
983 LogicalResult pushCyclicPrinting(
const void *opaquePointer)
override {
984 return success(cyclicPrintingStack.insert(opaquePointer));
987 void popCyclicPrinting()
override { cyclicPrintingStack.pop_back(); }
994 AliasInitializer &initializer;
1003 size_t maxAliasDepth = 0;
1006 mutable llvm::raw_null_ostream os;
1014 StringRef allowedPunctChars =
"$._-",
1015 bool allowTrailingDigit =
true) {
1016 assert(!name.empty() &&
"Shouldn't have an empty name here");
1018 auto validChar = [&](
char ch) {
1019 return llvm::isAlnum(ch) || allowedPunctChars.contains(ch);
1022 auto copyNameToBuffer = [&] {
1023 for (
char ch : name) {
1025 buffer.push_back(ch);
1027 buffer.push_back(
'_');
1029 buffer.append(llvm::utohexstr((
unsigned char)ch));
1036 if (isdigit(name[0]) || (!validChar(name[0]) && name[0] !=
' ')) {
1037 buffer.push_back(
'_');
1044 if (!allowTrailingDigit && isdigit(name.back())) {
1046 buffer.push_back(
'_');
1051 for (
char ch : name) {
1052 if (!validChar(ch)) {
1064 void AliasInitializer::initializeAliases(
1065 llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
1066 llvm::MapVector<const void *, SymbolAlias> &symbolToAlias) {
1068 unprocessedAliases = visitedSymbols.takeVector();
1069 llvm::stable_sort(unprocessedAliases, [](
const auto &lhs,
const auto &rhs) {
1070 return lhs.second < rhs.second;
1073 llvm::StringMap<unsigned> nameCounts;
1074 for (
auto &[symbol, aliasInfo] : unprocessedAliases) {
1075 if (!aliasInfo.alias)
1077 StringRef alias = *aliasInfo.alias;
1078 unsigned nameIndex = nameCounts[alias]++;
1079 symbolToAlias.insert(
1080 {symbol, SymbolAlias(alias, nameIndex, aliasInfo.isType,
1081 aliasInfo.canBeDeferred)});
1085 void AliasInitializer::initialize(
1087 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias) {
1091 DummyAliasOperationPrinter aliasPrinter(printerFlags, *
this);
1092 aliasPrinter.printCustomOrGenericOp(op);
1095 initializeAliases(aliases, attrTypeToAlias);
1098 template <
typename T,
typename... PrintArgs>
1099 std::pair<size_t, size_t> AliasInitializer::visitImpl(
1100 T value, llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
1101 bool canBeDeferred, PrintArgs &&...printArgs) {
1102 auto [it, inserted] =
1103 aliases.insert({value.getAsOpaquePointer(), InProgressAliasInfo()});
1104 size_t aliasIndex = std::distance(aliases.begin(), it);
1108 markAliasNonDeferrable(aliasIndex);
1109 return {
static_cast<size_t>(it->second.aliasDepth), aliasIndex};
1113 generateAlias(value, it->second, canBeDeferred);
1114 it->second.isType = std::is_base_of_v<Type, T>;
1115 it->second.canBeDeferred = canBeDeferred;
1119 DummyAliasDialectAsmPrinter printer(*
this, canBeDeferred, childAliases);
1120 size_t maxAliasDepth =
1121 printer.printAndVisitNestedAliases(value, printArgs...);
1124 it = std::next(aliases.begin(), aliasIndex);
1127 it->second.childIndices = std::move(childAliases);
1129 it->second.aliasDepth = maxAliasDepth + 1;
1132 return {(size_t)it->second.aliasDepth, aliasIndex};
1135 void AliasInitializer::markAliasNonDeferrable(
size_t aliasIndex) {
1136 auto *it = std::next(aliases.begin(), aliasIndex);
1140 if (!it->second.canBeDeferred)
1143 it->second.canBeDeferred =
false;
1146 for (
size_t childIndex : it->second.childIndices)
1147 markAliasNonDeferrable(childIndex);
1150 template <
typename T>
1151 void AliasInitializer::generateAlias(T symbol, InProgressAliasInfo &alias,
1152 bool canBeDeferred) {
1154 for (
const auto &interface : interfaces) {
1156 interface.getAlias(symbol, aliasOS);
1159 nameBuffer = std::move(aliasBuffer);
1160 assert(!nameBuffer.empty() &&
"expected valid alias name");
1165 if (nameBuffer.empty())
1172 name = name.copy(aliasAllocator);
1173 alias = InProgressAliasInfo(name);
1191 LogicalResult getAlias(
Attribute attr, raw_ostream &os)
const;
1195 LogicalResult getAlias(
Type ty, raw_ostream &os)
const;
1199 void printNonDeferredAliases(
AsmPrinter::Impl &p, NewLineCounter &newLine) {
1200 printAliases(p, newLine,
false);
1205 printAliases(p, newLine,
true);
1215 llvm::MapVector<const void *, SymbolAlias> attrTypeToAlias;
1218 llvm::BumpPtrAllocator aliasAllocator;
1222 void AliasState::initialize(
1225 AliasInitializer initializer(interfaces, aliasAllocator);
1226 initializer.initialize(op, printerFlags, attrTypeToAlias);
1229 LogicalResult AliasState::getAlias(
Attribute attr, raw_ostream &os)
const {
1231 if (it == attrTypeToAlias.end())
1233 it->second.print(os);
1237 LogicalResult AliasState::getAlias(
Type ty, raw_ostream &os)
const {
1239 if (it == attrTypeToAlias.end())
1241 if (!it->second.isPrinted)
1244 it->second.print(os);
1248 void AliasState::printAliases(
AsmPrinter::Impl &p, NewLineCounter &newLine,
1250 auto filterFn = [=](
const auto &aliasIt) {
1251 return aliasIt.second.canBeDeferred() == isDeferred;
1253 for (
auto &[opaqueSymbol, alias] :
1254 llvm::make_filter_range(attrTypeToAlias, filterFn)) {
1258 if (alias.isTypeAlias()) {
1261 alias.isPrinted =
true;
1288 class SSANameState {
1291 enum :
unsigned { NameSentinel = ~0U };
1294 SSANameState() =
default;
1299 void printValueID(
Value value,
bool printResultNo, raw_ostream &stream)
const;
1302 void printOperationID(
Operation *op, raw_ostream &stream)
const;
1309 BlockInfo getBlockInfo(
Block *block);
1318 void numberValuesInRegion(
Region ®ion);
1319 void numberValuesInBlock(
Block &block);
1326 void getResultIDAndNumber(
OpResult result,
Value &lookupValue,
1327 std::optional<int> &lookupResultNo)
const;
1330 void setValueName(
Value value, StringRef name);
1334 StringRef uniqueValueName(StringRef name);
1357 llvm::ScopedHashTable<StringRef, char> usedNames;
1358 llvm::BumpPtrAllocator usedNameAllocator;
1361 unsigned nextValueID = 0;
1363 unsigned nextArgumentID = 0;
1365 unsigned nextConflictID = 0;
1374 : printerFlags(printerFlags) {
1375 llvm::SaveAndRestore valueIDSaver(nextValueID);
1376 llvm::SaveAndRestore argumentIDSaver(nextArgumentID);
1377 llvm::SaveAndRestore conflictIDSaver(nextConflictID);
1382 using UsedNamesScopeTy = llvm::ScopedHashTable<StringRef, char>::ScopeTy;
1383 using NamingContext =
1384 std::tuple<Region *, unsigned, unsigned, unsigned, UsedNamesScopeTy *>;
1387 llvm::BumpPtrAllocator allocator;
1390 auto *topLevelNamesScope =
1391 new (allocator.Allocate<UsedNamesScopeTy>()) UsedNamesScopeTy(usedNames);
1395 nameContext.push_back(std::make_tuple(®ion, nextValueID, nextArgumentID,
1396 nextConflictID, topLevelNamesScope));
1398 numberValuesInOp(*op);
1400 while (!nameContext.empty()) {
1402 UsedNamesScopeTy *parentScope;
1406 std::tie(region, std::ignore, std::ignore, std::ignore, parentScope) =
1407 nameContext.pop_back_val();
1409 std::tie(region, nextValueID, nextArgumentID, nextConflictID,
1410 parentScope) = nameContext.pop_back_val();
1414 while (usedNames.getCurScope() != parentScope) {
1415 usedNames.getCurScope()->~UsedNamesScopeTy();
1416 assert((usedNames.getCurScope() !=
nullptr || parentScope ==
nullptr) &&
1417 "top level parentScope must be a nullptr");
1421 auto *curNamesScope =
new (allocator.Allocate<UsedNamesScopeTy>())
1422 UsedNamesScopeTy(usedNames);
1424 numberValuesInRegion(*region);
1428 nameContext.push_back(std::make_tuple(®ion, nextValueID,
1429 nextArgumentID, nextConflictID,
1434 while (usedNames.getCurScope() !=
nullptr)
1435 usedNames.getCurScope()->~UsedNamesScopeTy();
1438 void SSANameState::printValueID(
Value value,
bool printResultNo,
1439 raw_ostream &stream)
const {
1441 stream <<
"<<NULL VALUE>>";
1445 std::optional<int> resultNo;
1446 auto lookupValue = value;
1450 if (
OpResult result = dyn_cast<OpResult>(value))
1451 getResultIDAndNumber(result, lookupValue, resultNo);
1453 auto it = valueIDs.find(lookupValue);
1454 if (it == valueIDs.end()) {
1455 stream <<
"<<UNKNOWN SSA VALUE>>";
1460 if (it->second != NameSentinel) {
1461 stream << it->second;
1463 auto nameIt = valueNames.find(lookupValue);
1464 assert(nameIt != valueNames.end() &&
"Didn't have a name entry?");
1465 stream << nameIt->second;
1468 if (resultNo && printResultNo)
1469 stream <<
'#' << *resultNo;
1472 void SSANameState::printOperationID(
Operation *op, raw_ostream &stream)
const {
1473 auto it = operationIDs.find(op);
1474 if (it == operationIDs.end()) {
1475 stream <<
"<<UNKNOWN OPERATION>>";
1477 stream <<
'%' << it->second;
1482 auto it = opResultGroups.find(op);
1483 return it == opResultGroups.end() ?
ArrayRef<int>() : it->second;
1486 BlockInfo SSANameState::getBlockInfo(
Block *block) {
1487 auto it = blockNames.find(block);
1488 BlockInfo invalidBlock{-1,
"INVALIDBLOCK"};
1489 return it != blockNames.end() ? it->second : invalidBlock;
1492 void SSANameState::shadowRegionArgs(
Region ®ion,
ValueRange namesToUse) {
1493 assert(!region.
empty() &&
"cannot shadow arguments of an empty region");
1495 "incorrect number of names passed in");
1497 "only KnownIsolatedFromAbove ops can shadow names");
1500 for (
unsigned i = 0, e = namesToUse.size(); i != e; ++i) {
1501 auto nameToUse = namesToUse[i];
1502 if (nameToUse ==
nullptr)
1507 llvm::raw_svector_ostream nameStream(nameStr);
1508 printValueID(nameToUse,
true, nameStream);
1511 assert(valueIDs[nameToReplace] == NameSentinel);
1514 auto name = StringRef(nameStream.str()).drop_front();
1517 valueNames[nameToReplace] = name.copy(usedNameAllocator);
1523 StringRef maybeGetValueNameFromLoc(
Value value, StringRef name) {
1525 return maybeNameLoc.getName();
1530 void SSANameState::numberValuesInRegion(
Region ®ion) {
1531 auto setBlockArgNameFn = [&](
Value arg, StringRef name) {
1532 assert(!valueIDs.count(arg) &&
"arg numbered multiple times");
1533 assert(llvm::cast<BlockArgument>(arg).getOwner()->getParent() == ®ion &&
1534 "arg not defined in current region");
1536 name = maybeGetValueNameFromLoc(arg, name);
1537 setValueName(arg, name);
1542 if (
auto asmInterface = dyn_cast<OpAsmOpInterface>(op))
1543 asmInterface.getAsmBlockArgumentNames(region, setBlockArgNameFn);
1548 unsigned nextBlockID = 0;
1549 for (
auto &block : region) {
1552 auto blockInfoIt = blockNames.insert({&block, {-1,
""}});
1553 if (blockInfoIt.second) {
1557 llvm::raw_string_ostream(name) <<
"^bb" << nextBlockID;
1558 blockInfoIt.first->second.name = StringRef(name).copy(usedNameAllocator);
1560 blockInfoIt.first->second.ordering = nextBlockID++;
1562 numberValuesInBlock(block);
1566 void SSANameState::numberValuesInBlock(
Block &block) {
1571 llvm::raw_svector_ostream specialName(specialNameBuffer);
1573 if (valueIDs.count(arg))
1576 specialNameBuffer.resize(strlen(
"arg"));
1577 specialName << nextArgumentID++;
1579 StringRef specialNameStr = specialName.str();
1581 specialNameStr = maybeGetValueNameFromLoc(arg, specialNameStr);
1582 setValueName(arg, specialNameStr);
1586 for (
auto &op : block)
1587 numberValuesInOp(op);
1590 void SSANameState::numberValuesInOp(
Operation &op) {
1593 auto setResultNameFn = [&](
Value result, StringRef name) {
1594 assert(!valueIDs.count(result) &&
"result numbered multiple times");
1595 assert(result.
getDefiningOp() == &op &&
"result not defined by 'op'");
1597 name = maybeGetValueNameFromLoc(result, name);
1598 setValueName(result, name);
1601 if (
int resultNo = llvm::cast<OpResult>(result).getResultNumber())
1602 resultGroups.push_back(resultNo);
1605 auto setBlockNameFn = [&](
Block *block, StringRef name) {
1607 "getAsmBlockArgumentNames callback invoked on a block not directly "
1608 "nested under the current operation");
1609 assert(!blockNames.count(block) &&
"block numbered multiple times");
1612 if (name.data() != tmpBuffer.data()) {
1613 tmpBuffer.append(name);
1614 name = tmpBuffer.str();
1616 name = name.copy(usedNameAllocator);
1617 blockNames[block] = {-1, name};
1621 if (OpAsmOpInterface asmInterface = dyn_cast<OpAsmOpInterface>(&op)) {
1622 asmInterface.getAsmBlockNames(setBlockNameFn);
1623 asmInterface.getAsmResultNames(setResultNameFn);
1628 if (numResults == 0) {
1631 if (operationIDs.try_emplace(&op, nextValueID).second)
1640 setValueName(resultBegin, nameLoc.getName());
1645 if (valueIDs.try_emplace(resultBegin, nextValueID).second)
1649 if (resultGroups.size() != 1) {
1650 llvm::array_pod_sort(resultGroups.begin(), resultGroups.end());
1651 opResultGroups.try_emplace(&op, std::move(resultGroups));
1655 void SSANameState::getResultIDAndNumber(
1657 std::optional<int> &lookupResultNo)
const {
1665 auto resultGroupIt = opResultGroups.find(owner);
1666 if (resultGroupIt == opResultGroups.end()) {
1668 lookupResultNo = resultNo;
1675 const auto *it = llvm::upper_bound(resultGroups, resultNo);
1676 int groupResultNo = 0, groupSize = 0;
1679 if (it == resultGroups.end()) {
1680 groupResultNo = resultGroups.back();
1681 groupSize =
static_cast<int>(owner->
getNumResults()) - resultGroups.back();
1684 groupResultNo = *std::prev(it);
1685 groupSize = *it - groupResultNo;
1690 lookupResultNo = resultNo - groupResultNo;
1691 lookupValue = owner->
getResult(groupResultNo);
1694 void SSANameState::setValueName(
Value value, StringRef name) {
1697 valueIDs[value] = nextValueID++;
1701 valueIDs[value] = NameSentinel;
1702 valueNames[value] = uniqueValueName(name);
1705 StringRef SSANameState::uniqueValueName(StringRef name) {
1710 if (!usedNames.count(name)) {
1711 name = name.copy(usedNameAllocator);
1717 probeName.push_back(
'_');
1719 probeName += llvm::utostr(nextConflictID++);
1720 if (!usedNames.count(probeName)) {
1721 name = probeName.str().copy(usedNameAllocator);
1724 probeName.resize(name.size() + 1);
1728 usedNames.insert(name,
char());
1738 class DistinctState {
1744 uint64_t distinctCounter = 0;
1749 uint64_t DistinctState::getId(
DistinctAttr distinctAttr) {
1750 auto [it, inserted] =
1751 distinctAttrMap.try_emplace(distinctAttr, distinctCounter);
1754 return it->getSecond();
1761 AsmParsedResourceEntry::~AsmParsedResourceEntry() =
default;
1762 AsmResourceBuilder::~AsmResourceBuilder() =
default;
1763 AsmResourceParser::~AsmResourceParser() =
default;
1764 AsmResourcePrinter::~AsmResourcePrinter() =
default;
1768 case AsmResourceEntryKind::Blob:
1770 case AsmResourceEntryKind::Bool:
1772 case AsmResourceEntryKind::String:
1775 llvm_unreachable(
"unknown AsmResourceEntryKind");
1779 std::unique_ptr<ResourceCollection> &collection = keyToResources[key.str()];
1781 collection = std::make_unique<ResourceCollection>(key);
1785 std::vector<std::unique_ptr<AsmResourcePrinter>>
1787 std::vector<std::unique_ptr<AsmResourcePrinter>> printers;
1788 for (
auto &it : keyToResources) {
1789 ResourceCollection *collection = it.second.get();
1791 return collection->buildResources(op, builder);
1793 printers.emplace_back(
1799 LogicalResult FallbackAsmResourceMap::ResourceCollection::parseResource(
1803 FailureOr<AsmResourceBlob> blob = entry.
parseAsBlob();
1806 resources.emplace_back(entry.
getKey(), std::move(*blob));
1813 resources.emplace_back(entry.
getKey(), *value);
1820 resources.emplace_back(entry.
getKey(), std::move(*str));
1827 void FallbackAsmResourceMap::ResourceCollection::buildResources(
1829 for (
const auto &entry : resources) {
1830 if (
const auto *value = std::get_if<AsmResourceBlob>(&entry.value))
1832 else if (
const auto *value = std::get_if<bool>(&entry.value))
1834 else if (
const auto *value = std::get_if<std::string>(&entry.value))
1837 llvm_unreachable(
"unknown AsmResourceEntryKind");
1851 : interfaces(op->
getContext()), nameState(op, printerFlags),
1852 printerFlags(printerFlags), locationMap(locationMap) {}
1855 : interfaces(ctx), printerFlags(printerFlags), locationMap(locationMap) {}
1859 aliasState.initialize(op, printerFlags, interfaces);
1879 return llvm::make_pointee_range(externalResourcePrinters);
1889 (*locationMap)[op] = std::make_pair(line, col);
1895 return dialectResources;
1899 return success(cyclicPrintingStack.insert(opaquePointer));
1915 AliasState aliasState;
1918 SSANameState nameState;
1921 DistinctState distinctState;
1937 template <
typename Range>
1941 [&stream](
const auto &dimSize) {
1942 if (ShapedType::isDynamic(dimSize))
1960 return printerFlags;
1964 auto parentThreadId = llvm::get_threadid();
1966 if (parentThreadId == llvm::get_threadid()) {
1968 diag.print(llvm::dbgs());
1969 llvm::dbgs() <<
"\n";
1975 if (failed(
verify(op))) {
1976 LLVM_DEBUG(llvm::dbgs()
1978 <<
"' failed to verify and will be printed in generic form\n");
1982 return printerFlags;
2001 return impl->getPrinterFlags();
2005 std::unique_ptr<AsmResourcePrinter> printer) {
2006 impl->externalResourcePrinters.emplace_back(std::move(printer));
2011 return impl->getDialectResources();
2019 : os(os), state(state), printerFlags(state.getPrinterFlags()) {}
2027 printLocation(loc, allowAlias);
2033 if (!isTopLevel && succeeded(state.getAliasState().getAlias(loc, os)))
2037 .Case<OpaqueLoc>([&](OpaqueLoc loc) {
2038 printLocationInternal(loc.getFallbackLocation(), pretty);
2040 .Case<UnknownLoc>([&](UnknownLoc loc) {
2048 os << loc.getFilename().getValue();
2050 printEscapedString(loc.getFilename());
2051 if (loc.getEndColumn() == loc.getStartColumn() &&
2052 loc.getStartLine() == loc.getEndLine()) {
2053 os <<
':' << loc.getStartLine() <<
':' << loc.getStartColumn();
2056 if (loc.getStartLine() == loc.getEndLine()) {
2057 os <<
':' << loc.getStartLine() <<
':' << loc.getStartColumn()
2058 <<
" to :" << loc.getEndColumn();
2061 os <<
':' << loc.getStartLine() <<
':' << loc.getStartColumn() <<
" to "
2062 << loc.getEndLine() <<
':' << loc.getEndColumn();
2064 .Case<NameLoc>([&](NameLoc loc) {
2065 printEscapedString(loc.getName());
2068 auto childLoc = loc.getChildLoc();
2069 if (!llvm::isa<UnknownLoc>(childLoc)) {
2071 printLocationInternal(childLoc, pretty);
2075 .Case<CallSiteLoc>([&](CallSiteLoc loc) {
2080 printLocationInternal(callee, pretty);
2082 if (llvm::isa<NameLoc>(callee)) {
2083 if (llvm::isa<FileLineColLoc>(caller)) {
2086 os << newLine <<
" at ";
2089 os << newLine <<
" at ";
2094 printLocationInternal(caller, pretty);
2098 .Case<FusedLoc>([&](
FusedLoc loc) {
2101 if (
Attribute metadata = loc.getMetadata()) {
2109 [&](Location loc) { printLocationInternal(loc, pretty); },
2110 [&]() { os << ", "; });
2113 .Default([&](LocationAttr loc) {
2114 // Assumes that this is a dialect-specific attribute and prints it
2116 printAttribute(loc);
2122 static void printFloatValue(const APFloat &apValue, raw_ostream &os,
2123 bool *printedHex = nullptr) {
2124 // We would like to output the FP constant value in exponential notation,
2125 // but we cannot do this if doing so will lose precision. Check here to
2126 // make sure that we only output it in exponential format if we can parse
2127 // the value back and get the same value.
2128 bool isInf = apValue.isInfinity();
2129 bool isNaN = apValue.isNaN();
2130 if (!isInf && !isNaN) {
2131 SmallString<128> strValue;
2132 apValue.toString(strValue, /*FormatPrecision=*/6, /*FormatMaxPadding=*/0,
2133 /*TruncateZero=*/false);
2135 // Check to make sure that the stringized number is not some string like
2136 // "Inf" or NaN, that atof will accept, but the lexer will not. Check
2137 // that the string matches the "[-+]?[0-9]" regex.
2138 assert(((strValue[0] >= '0
' && strValue[0] <= '9') ||
2139 ((strValue[0] ==
'-' || strValue[0] ==
'+') &&
2140 (strValue[1] >=
'0' && strValue[1] <=
'9'))) &&
2141 "[-+]?[0-9] regex does not match!");
2145 if (APFloat(apValue.getSemantics(), strValue).bitwiseIsEqual(apValue)) {
2153 apValue.toString(strValue);
2156 if (strValue.str().contains(
'.')) {
2167 APInt apInt = apValue.bitcastToAPInt();
2168 apInt.toString(str, 16,
false,
2175 return printLocationInternal(loc,
true,
true);
2179 printLocationInternal(loc,
false,
true);
2187 state.getDialectResources()[resource.
getDialect()].insert(resource);
2195 if (symName.empty() || !isalpha(symName.front()))
2200 symName = symName.drop_while(
2201 [](
char c) {
return llvm::isAlnum(c) || c ==
'.' || c ==
'_'; });
2202 if (symName.empty())
2207 return symName.front() ==
'<' && symName.back() ==
'>';
2212 StringRef dialectName, StringRef symString) {
2213 os << symPrefix << dialectName;
2218 os <<
'.' << symString;
2222 os << '<' << symString << '>
';
2226 static bool isBareIdentifier(StringRef name) {
2227 // By making this unsigned, the value passed in to isalnum will always be
2228 // in the range 0-255. This is important when building with MSVC because
2229 // its implementation will assert. This situation can arise when dealing
2230 // with UTF-8 multibyte characters.
2231 if (name.empty() || (!isalpha(name[0]) && name[0] != '_
'))
2233 return llvm::all_of(name.drop_front(), [](unsigned char c) {
2234 return isalnum(c) || c == '_
' || c == '$
' || c == '.
';
2240 static void printKeywordOrString(StringRef keyword, raw_ostream &os) {
2241 // If it can be represented as a bare identifier, write it directly.
2242 if (isBareIdentifier(keyword)) {
2247 // Otherwise, output the keyword wrapped in quotes with proper escaping.
2249 printEscapedString(keyword, os);
2256 static void printSymbolReference(StringRef symbolRef, raw_ostream &os) {
2257 if (symbolRef.empty()) {
2258 os << "@<<INVALID EMPTY SYMBOL>>
";
2262 printKeywordOrString(symbolRef, os);
2265 // Print out a valid ElementsAttr that is succinct and can represent any
2266 // potential shape/type, for use when eliding a large ElementsAttr.
2268 // We choose to use a dense resource ElementsAttr literal with conspicuous
2269 // content to hopefully alert readers to the fact that this has been elided.
2270 static void printElidedElementsAttr(raw_ostream &os) {
2271 os << R"(dense_resource<__elided__>)
";
2274 LogicalResult AsmPrinter::Impl::printAlias(Attribute attr) {
2275 return state.getAliasState().getAlias(attr, os);
2278 LogicalResult AsmPrinter::Impl::printAlias(Type type) {
2279 return state.getAliasState().getAlias(type, os);
2282 void AsmPrinter::Impl::printAttribute(Attribute attr,
2283 AttrTypeElision typeElision) {
2285 os << "<<NULL ATTRIBUTE>>
";
2289 // Try to print an alias for this attribute.
2290 if (succeeded(printAlias(attr)))
2292 return printAttributeImpl(attr, typeElision);
2295 void AsmPrinter::Impl::printAttributeImpl(Attribute attr,
2296 AttrTypeElision typeElision) {
2297 if (!isa<BuiltinDialect>(attr.getDialect())) {
2298 printDialectAttribute(attr);
2299 } else if (auto opaqueAttr = llvm::dyn_cast<OpaqueAttr>(attr)) {
2300 printDialectSymbol(os, "#
", opaqueAttr.getDialectNamespace(),
2301 opaqueAttr.getAttrData());
2302 } else if (llvm::isa<UnitAttr>(attr)) {
2305 } else if (auto distinctAttr = llvm::dyn_cast<DistinctAttr>(attr)) {
2306 os << "distinct[
" << state.getDistinctState().getId(distinctAttr) << "]<
";
2307 if (!llvm::isa<UnitAttr>(distinctAttr.getReferencedAttr())) {
2308 printAttribute(distinctAttr.getReferencedAttr());
2312 } else if (auto dictAttr = llvm::dyn_cast<DictionaryAttr>(attr)) {
2314 interleaveComma(dictAttr.getValue(),
2315 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2318 } else if (auto intAttr = llvm::dyn_cast<IntegerAttr>(attr)) {
2319 Type intType = intAttr.getType();
2320 if (intType.isSignlessInteger(1)) {
2321 os << (intAttr.getValue().getBoolValue() ? "true" : "false");
2323 // Boolean integer attributes always elides the type.
2327 // Only print attributes as unsigned if they are explicitly unsigned or are
2328 // signless 1-bit values. Indexes, signed values, and multi-bit signless
2329 // values print as signed.
2331 intType.isUnsignedInteger() || intType.isSignlessInteger(1);
2332 intAttr.getValue().print(os, !isUnsigned);
2334 // IntegerAttr elides the type if I64.
2335 if (typeElision == AttrTypeElision::May && intType.isSignlessInteger(64))
2338 } else if (auto floatAttr = llvm::dyn_cast<FloatAttr>(attr)) {
2339 bool printedHex = false;
2340 printFloatValue(floatAttr.getValue(), os, &printedHex);
2342 // FloatAttr elides the type if F64.
2343 if (typeElision == AttrTypeElision::May && floatAttr.getType().isF64() &&
2347 } else if (auto strAttr = llvm::dyn_cast<StringAttr>(attr)) {
2348 printEscapedString(strAttr.getValue());
2350 } else if (auto arrayAttr = llvm::dyn_cast<ArrayAttr>(attr)) {
2352 interleaveComma(arrayAttr.getValue(), [&](Attribute attr) {
2353 printAttribute(attr, AttrTypeElision::May);
2357 } else if (auto affineMapAttr = llvm::dyn_cast<AffineMapAttr>(attr)) {
2358 os << "affine_map<
";
2359 affineMapAttr.getValue().print(os);
2362 // AffineMap always elides the type.
2365 } else if (auto integerSetAttr = llvm::dyn_cast<IntegerSetAttr>(attr)) {
2366 os << "affine_set<
";
2367 integerSetAttr.getValue().print(os);
2370 // IntegerSet always elides the type.
2373 } else if (auto typeAttr = llvm::dyn_cast<TypeAttr>(attr)) {
2374 printType(typeAttr.getValue());
2376 } else if (auto refAttr = llvm::dyn_cast<SymbolRefAttr>(attr)) {
2377 printSymbolReference(refAttr.getRootReference().getValue(), os);
2378 for (FlatSymbolRefAttr nestedRef : refAttr.getNestedReferences()) {
2380 printSymbolReference(nestedRef.getValue(), os);
2383 } else if (auto intOrFpEltAttr =
2384 llvm::dyn_cast<DenseIntOrFPElementsAttr>(attr)) {
2385 if (printerFlags.shouldElideElementsAttr(intOrFpEltAttr)) {
2386 printElidedElementsAttr(os);
2389 printDenseIntOrFPElementsAttr(intOrFpEltAttr, /*allowHex=*/true);
2393 } else if (auto strEltAttr = llvm::dyn_cast<DenseStringElementsAttr>(attr)) {
2394 if (printerFlags.shouldElideElementsAttr(strEltAttr)) {
2395 printElidedElementsAttr(os);
2398 printDenseStringElementsAttr(strEltAttr);
2402 } else if (auto sparseEltAttr = llvm::dyn_cast<SparseElementsAttr>(attr)) {
2403 if (printerFlags.shouldElideElementsAttr(sparseEltAttr.getIndices()) ||
2404 printerFlags.shouldElideElementsAttr(sparseEltAttr.getValues())) {
2405 printElidedElementsAttr(os);
2408 DenseIntElementsAttr indices = sparseEltAttr.getIndices();
2409 if (indices.getNumElements() != 0) {
2410 printDenseIntOrFPElementsAttr(indices, /*allowHex=*/false);
2412 printDenseElementsAttr(sparseEltAttr.getValues(), /*allowHex=*/true);
2416 } else if (auto stridedLayoutAttr = llvm::dyn_cast<StridedLayoutAttr>(attr)) {
2417 stridedLayoutAttr.print(os);
2418 } else if (auto denseArrayAttr = llvm::dyn_cast<DenseArrayAttr>(attr)) {
2420 printType(denseArrayAttr.getElementType());
2421 if (!denseArrayAttr.empty()) {
2423 printDenseArrayAttr(denseArrayAttr);
2427 } else if (auto resourceAttr =
2428 llvm::dyn_cast<DenseResourceElementsAttr>(attr)) {
2429 os << "dense_resource<
";
2430 printResourceHandle(resourceAttr.getRawHandle());
2432 } else if (auto locAttr = llvm::dyn_cast<LocationAttr>(attr)) {
2433 printLocation(locAttr);
2435 llvm::report_fatal_error("Unknown builtin attribute
");
2437 // Don't print the type if we must elide it, or if it is a None type.
2438 if (typeElision != AttrTypeElision::Must) {
2439 if (auto typedAttr = llvm::dyn_cast<TypedAttr>(attr)) {
2440 Type attrType = typedAttr.getType();
2441 if (!llvm::isa<NoneType>(attrType)) {
2443 printType(attrType);
2450 static void printDenseIntElement(const APInt &value, raw_ostream &os,
2452 if (type.isInteger(1))
2453 os << (value.getBoolValue() ? "
true" : "false");
2455 value.print(os, !type.isUnsignedInteger());
2459 printDenseElementsAttrImpl(bool isSplat, ShapedType type, raw_ostream &os,
2460 function_ref<void(unsigned)> printEltFn) {
2461 // Special case for 0-d and splat tensors.
2463 return printEltFn(0);
2465 // Special case for degenerate tensors.
2466 auto numElements = type.getNumElements();
2467 if (numElements == 0)
2470 // We use a mixed-radix counter to iterate through the shape. When we bump a
2471 // non-least-significant digit, we emit a close bracket. When we next emit an
2472 // element we re-open all closed brackets.
2474 // The mixed-radix counter, with radices in 'shape'.
2475 int64_t rank = type.getRank();
2476 SmallVector<unsigned, 4> counter(rank, 0);
2477 // The number of brackets that have been opened and not closed.
2478 unsigned openBrackets = 0;
2480 auto shape = type.getShape();
2481 auto bumpCounter = [&] {
2482 // Bump the least significant digit.
2483 ++counter[rank - 1];
2484 // Iterate backwards bubbling back the increment.
2485 for (unsigned i = rank - 1; i > 0; --i)
2486 if (counter[i] >= shape[i]) {
2487 // Index 'i' is rolled over. Bump (i-1) and close a bracket.
2495 for (unsigned idx = 0, e = numElements; idx != e; ++idx) {
2498 while (openBrackets++ < rank)
2500 openBrackets = rank;
2504 while (openBrackets-- > 0)
2508 void AsmPrinter::Impl::printDenseElementsAttr(DenseElementsAttr attr,
2510 if (auto stringAttr = llvm::dyn_cast<DenseStringElementsAttr>(attr))
2511 return printDenseStringElementsAttr(stringAttr);
2513 printDenseIntOrFPElementsAttr(llvm::cast<DenseIntOrFPElementsAttr>(attr),
2517 void AsmPrinter::Impl::printDenseIntOrFPElementsAttr(
2518 DenseIntOrFPElementsAttr attr, bool allowHex) {
2519 auto type = attr.getType();
2520 auto elementType = type.getElementType();
2522 // Check to see if we should format this attribute as a hex string.
2523 if (allowHex && printerFlags.shouldPrintElementsAttrWithHex(attr)) {
2524 ArrayRef<char> rawData = attr.getRawData();
2525 if (llvm::endianness::native == llvm::endianness::big) {
2526 // Convert endianess in big-endian(BE) machines. `rawData` is BE in BE
2527 // machines. It is converted here to print in LE format.
2528 SmallVector<char, 64> outDataVec(rawData.size());
2529 MutableArrayRef<char> convRawData(outDataVec);
2530 DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
2531 rawData, convRawData, type);
2532 printHexString(convRawData);
2534 printHexString(rawData);
2540 if (ComplexType complexTy = llvm::dyn_cast<ComplexType>(elementType)) {
2541 Type complexElementType = complexTy.getElementType();
2542 // Note: The if and else below had a common lambda function which invoked
2543 // printDenseElementsAttrImpl. This lambda was hitting a bug in gcc 9.1,9.2
2544 // and hence was replaced.
2545 if (llvm::isa<IntegerType>(complexElementType)) {
2546 auto valueIt = attr.value_begin<std::complex<APInt>>();
2547 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2548 auto complexValue = *(valueIt + index);
2550 printDenseIntElement(complexValue.real(), os, complexElementType);
2552 printDenseIntElement(complexValue.imag(), os, complexElementType);
2556 auto valueIt = attr.value_begin<std::complex<APFloat>>();
2557 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2558 auto complexValue = *(valueIt + index);
2560 printFloatValue(complexValue.real(), os);
2562 printFloatValue(complexValue.imag(), os);
2566 } else if (elementType.isIntOrIndex()) {
2567 auto valueIt = attr.value_begin<APInt>();
2568 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2569 printDenseIntElement(*(valueIt + index), os, elementType);
2572 assert(llvm::isa<FloatType>(elementType) && "unexpected element type
");
2573 auto valueIt = attr.value_begin<APFloat>();
2574 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2575 printFloatValue(*(valueIt + index), os);
2580 void AsmPrinter::Impl::printDenseStringElementsAttr(
2581 DenseStringElementsAttr attr) {
2582 ArrayRef<StringRef> data = attr.getRawStringData();
2583 auto printFn = [&](unsigned index) { printEscapedString(data[index]); };
2584 printDenseElementsAttrImpl(attr.isSplat(), attr.getType(), os, printFn);
2587 void AsmPrinter::Impl::printDenseArrayAttr(DenseArrayAttr attr) {
2588 Type type = attr.getElementType();
2589 unsigned bitwidth = type.isInteger(1) ? 8 : type.getIntOrFloatBitWidth();
2590 unsigned byteSize = bitwidth / 8;
2591 ArrayRef<char> data = attr.getRawData();
2593 auto printElementAt = [&](unsigned i) {
2594 APInt value(bitwidth, 0);
2596 llvm::LoadIntFromMemory(
2597 value, reinterpret_cast<const uint8_t *>(data.begin() + byteSize * i),
2600 // Print the data as-is or as a float.
2601 if (type.isIntOrIndex()) {
2602 printDenseIntElement(value, getStream(), type);
2604 APFloat fltVal(llvm::cast<FloatType>(type).getFloatSemantics(), value);
2605 printFloatValue(fltVal, getStream());
2608 llvm::interleaveComma(llvm::seq<unsigned>(0, attr.size()), getStream(),
2612 void AsmPrinter::Impl::printType(Type type) {
2614 os << "<<NULL TYPE>>
";
2618 // Try to print an alias for this type.
2619 if (succeeded(printAlias(type)))
2621 return printTypeImpl(type);
2624 void AsmPrinter::Impl::printTypeImpl(Type type) {
2625 TypeSwitch<Type>(type)
2626 .Case<OpaqueType>([&](OpaqueType opaqueTy) {
2627 printDialectSymbol(os, "!
", opaqueTy.getDialectNamespace(),
2628 opaqueTy.getTypeData());
2630 .Case<IndexType>([&](Type) { os << "index
"; })
2631 .Case<Float4E2M1FNType>([&](Type) { os << "f4E2M1FN
"; })
2632 .Case<Float6E2M3FNType>([&](Type) { os << "f6E2M3FN
"; })
2633 .Case<Float6E3M2FNType>([&](Type) { os << "f6E3M2FN
"; })
2634 .Case<Float8E5M2Type>([&](Type) { os << "f8E5M2
"; })
2635 .Case<Float8E4M3Type>([&](Type) { os << "f8E4M3
"; })
2636 .Case<Float8E4M3FNType>([&](Type) { os << "f8E4M3FN
"; })
2637 .Case<Float8E5M2FNUZType>([&](Type) { os << "f8E5M2FNUZ
"; })
2638 .Case<Float8E4M3FNUZType>([&](Type) { os << "f8E4M3FNUZ
"; })
2639 .Case<Float8E4M3B11FNUZType>([&](Type) { os << "f8E4M3B11FNUZ
"; })
2640 .Case<Float8E3M4Type>([&](Type) { os << "f8E3M4
"; })
2641 .Case<Float8E8M0FNUType>([&](Type) { os << "f8E8M0FNU
"; })
2642 .Case<BFloat16Type>([&](Type) { os << "bf16"; })
2643 .Case<Float16Type>([&](Type) { os << "f16"; })
2644 .Case<FloatTF32Type>([&](Type) { os << "tf32
"; })
2645 .Case<Float32Type>([&](Type) { os << "f32
"; })
2646 .Case<Float64Type>([&](Type) { os << "f64
"; })
2647 .Case<Float80Type>([&](Type) { os << "f80
"; })
2648 .Case<Float128Type>([&](Type) { os << "f128
"; })
2649 .Case<IntegerType>([&](IntegerType integerTy) {
2650 if (integerTy.isSigned())
2652 else if (integerTy.isUnsigned())
2654 os << 'i' << integerTy.getWidth();
2656 .Case<FunctionType>([&](FunctionType funcTy) {
2658 interleaveComma(funcTy.getInputs(), [&](Type ty) { printType(ty); });
2660 ArrayRef<Type> results = funcTy.getResults();
2661 if (results.size() == 1 && !llvm::isa<FunctionType>(results[0])) {
2662 printType(results[0]);
2665 interleaveComma(results, [&](Type ty) { printType(ty); });
2669 .Case<VectorType>([&](VectorType vectorTy) {
2670 auto scalableDims = vectorTy.getScalableDims();
2672 auto vShape = vectorTy.getShape();
2673 unsigned lastDim = vShape.size();
2674 unsigned dimIdx = 0;
2675 for (dimIdx = 0; dimIdx < lastDim; dimIdx++) {
2676 if (!scalableDims.empty() && scalableDims[dimIdx])
2678 os << vShape[dimIdx];
2679 if (!scalableDims.empty() && scalableDims[dimIdx])
2683 printType(vectorTy.getElementType());
2686 .Case<RankedTensorType>([&](RankedTensorType tensorTy) {
2688 printDimensionList(tensorTy.getShape());
2689 if (!tensorTy.getShape().empty())
2691 printType(tensorTy.getElementType());
2692 // Only print the encoding attribute value if set.
2693 if (tensorTy.getEncoding()) {
2695 printAttribute(tensorTy.getEncoding());
2699 .Case<UnrankedTensorType>([&](UnrankedTensorType tensorTy) {
2701 printType(tensorTy.getElementType());
2704 .Case<MemRefType>([&](MemRefType memrefTy) {
2706 printDimensionList(memrefTy.getShape());
2707 if (!memrefTy.getShape().empty())
2709 printType(memrefTy.getElementType());
2710 MemRefLayoutAttrInterface layout = memrefTy.getLayout();
2711 if (!llvm::isa<AffineMapAttr>(layout) || !layout.isIdentity()) {
2713 printAttribute(memrefTy.getLayout(), AttrTypeElision::May);
2715 // Only print the memory space if it is the non-default one.
2716 if (memrefTy.getMemorySpace()) {
2718 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2722 .Case<UnrankedMemRefType>([&](UnrankedMemRefType memrefTy) {
2724 printType(memrefTy.getElementType());
2725 // Only print the memory space if it is the non-default one.
2726 if (memrefTy.getMemorySpace()) {
2728 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2732 .Case<ComplexType>([&](ComplexType complexTy) {
2734 printType(complexTy.getElementType());
2737 .Case<TupleType>([&](TupleType tupleTy) {
2739 interleaveComma(tupleTy.getTypes(),
2740 [&](Type type) { printType(type); });
2743 .Case<NoneType>([&](Type) { os << "none
"; })
2744 .Default([&](Type type) { return printDialectType(type); });
2747 void AsmPrinter::Impl::printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
2748 ArrayRef<StringRef> elidedAttrs,
2750 // If there are no attributes, then there is nothing to be done.
2754 // Functor used to print a filtered attribute list.
2755 auto printFilteredAttributesFn = [&](auto filteredAttrs) {
2756 // Print the 'attributes' keyword if necessary.
2758 os << " attributes
";
2760 // Otherwise, print them all out in braces.
2762 interleaveComma(filteredAttrs,
2763 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2767 // If no attributes are elided, we can directly print with no filtering.
2768 if (elidedAttrs.empty())
2769 return printFilteredAttributesFn(attrs);
2771 // Otherwise, filter out any attributes that shouldn't be included.
2772 llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
2774 auto filteredAttrs = llvm::make_filter_range(attrs, [&](NamedAttribute attr) {
2775 return !elidedAttrsSet.contains(attr.getName().strref());
2777 if (!filteredAttrs.empty())
2778 printFilteredAttributesFn(filteredAttrs);
2780 void AsmPrinter::Impl::printNamedAttribute(NamedAttribute attr) {
2781 // Print the name without quotes if possible.
2782 ::printKeywordOrString(attr.getName().strref(), os);
2784 // Pretty printing elides the attribute value for unit attributes.
2785 if (llvm::isa<UnitAttr>(attr.getValue()))
2789 printAttribute(attr.getValue());
2792 void AsmPrinter::Impl::printDialectAttribute(Attribute attr) {
2793 auto &dialect = attr.getDialect();
2795 // Ask the dialect to serialize the attribute to a string.
2796 std::string attrName;
2798 llvm::raw_string_ostream attrNameStr(attrName);
2799 Impl subPrinter(attrNameStr, state);
2800 DialectAsmPrinter printer(subPrinter);
2801 dialect.printAttribute(attr, printer);
2803 printDialectSymbol(os, "#
", dialect.getNamespace(), attrName);
2806 void AsmPrinter::Impl::printDialectType(Type type) {
2807 auto &dialect = type.getDialect();
2809 // Ask the dialect to serialize the type to a string.
2810 std::string typeName;
2812 llvm::raw_string_ostream typeNameStr(typeName);
2813 Impl subPrinter(typeNameStr, state);
2814 DialectAsmPrinter printer(subPrinter);
2815 dialect.printType(type, printer);
2817 printDialectSymbol(os, "!
", dialect.getNamespace(), typeName);
2820 void AsmPrinter::Impl::printEscapedString(StringRef str) {
2822 llvm::printEscapedString(str, os);
2827 os <<
"\"0x" << llvm::toHex(str) <<
"\"";
2830 printHexString(StringRef(data.data(), data.size()));
2834 return state.pushCyclicPrinting(opaquePointer);
2850 assert(
impl &&
"expected AsmPrinter::getStream to be overriden");
2851 return impl->getStream();
2856 assert(
impl &&
"expected AsmPrinter::printFloat to be overriden");
2861 assert(
impl &&
"expected AsmPrinter::printType to be overriden");
2862 impl->printType(type);
2866 assert(
impl &&
"expected AsmPrinter::printAttribute to be overriden");
2867 impl->printAttribute(attr);
2871 assert(
impl &&
"expected AsmPrinter::printAlias to be overriden");
2872 return impl->printAlias(attr);
2876 assert(
impl &&
"expected AsmPrinter::printAlias to be overriden");
2877 return impl->printAlias(type);
2882 "expected AsmPrinter::printAttributeWithoutType to be overriden");
2887 assert(
impl &&
"expected AsmPrinter::printKeywordOrString to be overriden");
2892 assert(
impl &&
"expected AsmPrinter::printString to be overriden");
2894 printEscapedString(keyword,
getStream());
2899 assert(
impl &&
"expected AsmPrinter::printSymbolName to be overriden");
2904 assert(
impl &&
"expected AsmPrinter::printResourceHandle to be overriden");
2905 impl->printResourceHandle(resource);
2913 return impl->pushCyclicPrinting(opaquePointer);
2924 printAffineExprInternal(expr, BindingStrength::Weak, printValueName);
2930 const char *binopSpelling =
nullptr;
2933 unsigned pos = cast<AffineSymbolExpr>(expr).getPosition();
2935 printValueName(pos,
true);
2941 unsigned pos = cast<AffineDimExpr>(expr).getPosition();
2943 printValueName(pos,
false);
2949 os << cast<AffineConstantExpr>(expr).getValue();
2952 binopSpelling =
" + ";
2955 binopSpelling =
" * ";
2958 binopSpelling =
" floordiv ";
2961 binopSpelling =
" ceildiv ";
2964 binopSpelling =
" mod ";
2968 auto binOp = cast<AffineBinaryOpExpr>(expr);
2974 if (enclosingTightness == BindingStrength::Strong)
2978 auto rhsConst = dyn_cast<AffineConstantExpr>(rhsExpr);
2980 rhsConst.getValue() == -1) {
2982 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
2983 if (enclosingTightness == BindingStrength::Strong)
2988 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
2990 os << binopSpelling;
2991 printAffineExprInternal(rhsExpr, BindingStrength::Strong, printValueName);
2993 if (enclosingTightness == BindingStrength::Strong)
2999 if (enclosingTightness == BindingStrength::Strong)
3004 if (
auto rhs = dyn_cast<AffineBinaryOpExpr>(rhsExpr)) {
3007 if (
auto rrhs = dyn_cast<AffineConstantExpr>(rrhsExpr)) {
3008 if (rrhs.getValue() == -1) {
3009 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
3013 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
3016 printAffineExprInternal(rhs.getLHS(), BindingStrength::Weak,
3020 if (enclosingTightness == BindingStrength::Strong)
3025 if (rrhs.getValue() < -1) {
3026 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
3029 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
3031 os <<
" * " << -rrhs.getValue();
3032 if (enclosingTightness == BindingStrength::Strong)
3041 if (
auto rhsConst = dyn_cast<AffineConstantExpr>(rhsExpr)) {
3042 if (rhsConst.getValue() < 0) {
3043 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
3044 os <<
" - " << -rhsConst.getValue();
3045 if (enclosingTightness == BindingStrength::Strong)
3051 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
3054 printAffineExprInternal(rhsExpr, BindingStrength::Weak, printValueName);
3056 if (enclosingTightness == BindingStrength::Strong)
3061 printAffineExprInternal(expr, BindingStrength::Weak);
3062 isEq ? os <<
" == 0" : os <<
" >= 0";
3068 for (
int i = 0; i < (int)map.
getNumDims() - 1; ++i)
3069 os <<
'd' << i <<
", ";
3078 os <<
's' << i <<
", ";
3087 [&](
AffineExpr expr) { printAffineExpr(expr); });
3094 for (
unsigned i = 1; i < set.
getNumDims(); ++i)
3095 os <<
'd' << i - 1 <<
", ";
3104 os <<
's' << i <<
", ";
3113 for (
int i = 1; i < numConstraints; ++i) {
3117 if (numConstraints >= 1)
3118 printAffineConstraint(set.
getConstraint(numConstraints - 1),
3119 set.
isEq(numConstraints - 1));
3134 explicit OperationPrinter(raw_ostream &os,
AsmStateImpl &state)
3138 void printTopLevelOperation(
Operation *op);
3142 void printFullOpWithIndentAndLoc(
Operation *op);
3148 void printCustomOrGenericOp(
Operation *op)
override;
3150 void printGenericOp(
Operation *op,
bool printOpName)
override;
3153 void printBlockName(
Block *block);
3158 void print(
Block *block,
bool printBlockArgs =
true,
3159 bool printBlockTerminator =
true);
3162 void printValueID(
Value value,
bool printResultNo =
true,
3163 raw_ostream *streamOverride =
nullptr)
const;
3167 raw_ostream *streamOverride =
nullptr)
const;
3175 void printOptionalLocationSpecifier(
Location loc)
override {
3176 printTrailingLocation(loc);
3183 os.indent(currentIndent);
3187 void increaseIndent()
override { currentIndent += indentWidth; }
3190 void decreaseIndent()
override { currentIndent -= indentWidth; }
3199 bool omitType =
false)
override;
3202 void printOperand(
Value value)
override { printValueID(value); }
3203 void printOperand(
Value value, raw_ostream &os)
override {
3204 printValueID(value,
true, &os);
3212 void printOptionalAttrDictWithKeyword(
3220 void printSuccessor(
Block *successor)
override;
3224 void printSuccessorAndUseList(
Block *successor,
3229 bool printBlockTerminators,
bool printEmptyBlock)
override;
3236 state.getSSANameState().shadowRegionArgs(region, namesToUse);
3241 void printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3256 void printValueUsers(
Value value);
3260 void printUserIDs(
Operation *user,
bool prefixComma =
false);
3268 using PrintFn =
function_ref<void(StringRef, ValueFn)>;
3270 ResourceBuilder(PrintFn printFn) : printFn(printFn) {}
3271 ~ResourceBuilder()
override =
default;
3273 void buildBool(StringRef key,
bool data)
final {
3274 printFn(key, [&](raw_ostream &os) { os << (data ?
"true" :
"false"); });
3277 void buildString(StringRef key, StringRef data)
final {
3278 printFn(key, [&](raw_ostream &os) {
3280 llvm::printEscapedString(data, os);
3286 uint32_t dataAlignment)
final {
3287 printFn(key, [&](raw_ostream &os) {
3289 llvm::support::ulittle32_t dataAlignmentLE(dataAlignment);
3291 << llvm::toHex(StringRef(
reinterpret_cast<char *
>(&dataAlignmentLE),
3292 sizeof(dataAlignment)))
3293 << llvm::toHex(StringRef(data.data(), data.size())) <<
"\"";
3302 void printFileMetadataDictionary(
Operation *op);
3308 void printResourceFileMetadata(
function_ref<
void()> checkAddMetadataDict,
3319 const static unsigned indentWidth = 2;
3322 unsigned currentIndent = 0;
3326 void OperationPrinter::printTopLevelOperation(
Operation *op) {
3328 state.getAliasState().printNonDeferredAliases(*
this, newLine);
3331 printFullOpWithIndentAndLoc(op);
3335 state.getAliasState().printDeferredAliases(*
this, newLine);
3338 printFileMetadataDictionary(op);
3341 void OperationPrinter::printFileMetadataDictionary(
Operation *op) {
3342 bool sawMetadataEntry =
false;
3343 auto checkAddMetadataDict = [&] {
3344 if (!std::exchange(sawMetadataEntry,
true))
3345 os << newLine <<
"{-#" << newLine;
3349 printResourceFileMetadata(checkAddMetadataDict, op);
3352 if (sawMetadataEntry)
3353 os << newLine <<
"#-}" << newLine;
3356 void OperationPrinter::printResourceFileMetadata(
3359 bool hadResource =
false;
3360 bool needResourceComma =
false;
3361 bool needEntryComma =
false;
3362 auto processProvider = [&](StringRef dictName, StringRef name,
auto &provider,
3363 auto &&...providerArgs) {
3364 bool hadEntry =
false;
3365 auto printFn = [&](StringRef key, ResourceBuilder::ValueFn valueFn) {
3366 checkAddMetadataDict();
3368 auto printFormatting = [&]() {
3370 if (!std::exchange(hadResource,
true)) {
3371 if (needResourceComma)
3372 os <<
"," << newLine;
3373 os <<
" " << dictName <<
"_resources: {" << newLine;
3376 if (!std::exchange(hadEntry,
true)) {
3378 os <<
"," << newLine;
3379 os <<
" " << name <<
": {" << newLine;
3381 os <<
"," << newLine;
3385 std::optional<uint64_t> charLimit =
3387 if (charLimit.has_value()) {
3388 std::string resourceStr;
3389 llvm::raw_string_ostream ss(resourceStr);
3393 if (resourceStr.size() > charLimit.value())
3397 os <<
" " << key <<
": " << resourceStr;
3400 os <<
" " << key <<
": ";
3404 ResourceBuilder entryBuilder(printFn);
3405 provider.buildResources(op, providerArgs..., entryBuilder);
3407 needEntryComma |= hadEntry;
3409 os << newLine <<
" }";
3415 auto &dialectResources = state.getDialectResources();
3416 StringRef name = interface.getDialect()->getNamespace();
3417 auto it = dialectResources.find(interface.getDialect());
3418 if (it != dialectResources.end())
3419 processProvider(
"dialect", name, interface, it->second);
3421 processProvider(
"dialect", name, interface,
3425 os << newLine <<
" }";
3429 needEntryComma =
false;
3430 needResourceComma = hadResource;
3431 hadResource =
false;
3432 for (
const auto &printer : state.getResourcePrinters())
3433 processProvider(
"external", printer.getName(), printer);
3435 os << newLine <<
" }";
3443 void OperationPrinter::printRegionArgument(
BlockArgument arg,
3451 printOptionalAttrDict(argAttrs);
3453 printTrailingLocation(arg.
getLoc(),
false);
3456 void OperationPrinter::printFullOpWithIndentAndLoc(
Operation *op) {
3458 state.registerOperationLocation(op, newLine.curLine, currentIndent);
3460 os.indent(currentIndent);
3462 printTrailingLocation(op->
getLoc());
3464 printUsersComment(op);
3467 void OperationPrinter::printFullOp(
Operation *op) {
3469 auto printResultGroup = [&](
size_t resultNo,
size_t resultCount) {
3470 printValueID(op->
getResult(resultNo),
false);
3471 if (resultCount > 1)
3472 os <<
':' << resultCount;
3476 ArrayRef<int> resultGroups = state.getSSANameState().getOpResultGroups(op);
3477 if (!resultGroups.empty()) {
3480 interleaveComma(llvm::seq<int>(0, resultGroups.size() - 1), [&](
int i) {
3481 printResultGroup(resultGroups[i],
3482 resultGroups[i + 1] - resultGroups[i]);
3485 printResultGroup(resultGroups.back(), numResults - resultGroups.back());
3488 printResultGroup(0, numResults);
3494 printCustomOrGenericOp(op);
3497 void OperationPrinter::printUsersComment(
Operation *op) {
3501 printOperationID(op);
3502 }
else if (numResults && op->
use_empty()) {
3504 }
else if (numResults && !op->
use_empty()) {
3507 unsigned usedInNResults = 0;
3508 unsigned usedInNOperations = 0;
3511 if (userSet.insert(user).second) {
3512 ++usedInNOperations;
3513 usedInNResults += user->getNumResults();
3518 bool exactlyOneUniqueUse =
3519 usedInNResults <= 1 && usedInNOperations <= 1 && numResults == 1;
3520 os <<
" // " << (exactlyOneUniqueUse ?
"user" :
"users") <<
": ";
3521 bool shouldPrintBrackets = numResults > 1;
3522 auto printOpResult = [&](
OpResult opResult) {
3523 if (shouldPrintBrackets)
3525 printValueUsers(opResult);
3526 if (shouldPrintBrackets)
3530 interleaveComma(op->
getResults(), printOpResult);
3534 void OperationPrinter::printUsersComment(
BlockArgument arg) {
3540 os <<
" is used by ";
3541 printValueUsers(arg);
3546 void OperationPrinter::printValueUsers(
Value value) {
3554 if (userSet.insert(user).second)
3555 printUserIDs(user, index);
3559 void OperationPrinter::printUserIDs(
Operation *user,
bool prefixComma) {
3564 printOperationID(user);
3567 [
this](
Value result) { printValueID(result); });
3571 void OperationPrinter::printCustomOrGenericOp(
Operation *op) {
3577 opInfo->printAssembly(op, *
this, defaultDialectStack.back());
3582 if (
auto opPrinter = dialect->getOperationPrinter(op)) {
3587 if (name.count(
'.') == 1)
3588 name.consume_front((defaultDialectStack.back() +
".").str());
3592 opPrinter(op, *
this);
3599 printGenericOp(op,
true);
3602 void OperationPrinter::printGenericOp(
Operation *op,
bool printOpName) {
3606 interleaveComma(op->
getOperands(), [&](
Value value) { printValueID(value); });
3613 [&](
Block *successor) { printBlockName(successor); });
3625 if (op->getNumRegions() != 0) {
3627 interleaveComma(op->getRegions(), [&](Region ®ion) {
3628 printRegion(region, /*printEntryBlockArgs=*/true,
3629 /*printBlockTerminators=*/true, /*printEmptyBlock=*/true);
3634 printOptionalAttrDict(op->getPropertiesStorage()
3635 ? llvm::to_vector(op->getDiscardableAttrs())
3638 // Print the type signature of the operation.
3640 printFunctionalType(op);
3643 void OperationPrinter::printBlockName(Block *block) {
3644 os << state.getSSANameState().getBlockInfo(block).name;
3647 void OperationPrinter::print(Block *block, bool printBlockArgs,
3648 bool printBlockTerminator) {
3649 // Print the block label and argument list if requested.
3650 if (printBlockArgs) {
3651 os.indent(currentIndent);
3652 printBlockName(block);
3654 // Print the argument list if non-empty.
3655 if (!block->args_empty()) {
3657 interleaveComma(block->getArguments(), [&](BlockArgument arg) {
3660 printType(arg.getType());
3661 // TODO: We should allow location aliases on block arguments.
3662 printTrailingLocation(arg.getLoc(), /*allowAlias*/ false);
3668 // Print out some context information about the predecessors of this block.
3669 if (!block->getParent()) {
3670 os << " // block is not in a region!";
3671 } else if (block->hasNoPredecessors()) {
3672 if (!block->isEntryBlock())
3673 os << " // no predecessors";
3674 } else if (auto *pred = block->getSinglePredecessor()) {
3676 printBlockName(pred);
3678 // We want to print the predecessors in a stable order, not in
3679 // whatever order the use-list is in, so gather and sort them.
3680 SmallVector<BlockInfo, 4> predIDs;
3681 for (auto *pred : block->getPredecessors())
3682 predIDs.push_back(state.getSSANameState().getBlockInfo(pred));
3683 llvm::sort(predIDs, [](BlockInfo lhs, BlockInfo rhs) {
3684 return lhs.ordering < rhs.ordering;
3687 os << " // " << predIDs.size() << " preds: ";
3689 interleaveComma(predIDs, [&](BlockInfo pred) { os << pred.name; });
3694 currentIndent += indentWidth;
3696 if (printerFlags.shouldPrintValueUsers()) {
3697 for (BlockArgument arg : block->getArguments()) {
3698 os.indent(currentIndent);
3699 printUsersComment(arg);
3703 bool hasTerminator =
3704 !block->empty() && block->back().hasTrait<OpTrait::IsTerminator>();
3705 auto range = llvm::make_range(
3707 std::prev(block->end(),
3708 (!hasTerminator || printBlockTerminator) ? 0 : 1));
3709 for (auto &op : range) {
3710 printFullOpWithIndentAndLoc(&op);
3713 currentIndent -= indentWidth;
3716 void OperationPrinter::printValueID(Value value, bool printResultNo,
3717 raw_ostream *streamOverride) const {
3718 state.getSSANameState().printValueID(value, printResultNo,
3719 streamOverride ? *streamOverride : os);
3722 void OperationPrinter::printOperationID(Operation *op,
3723 raw_ostream *streamOverride) const {
3724 state.getSSANameState().printOperationID(op, streamOverride ? *streamOverride
3728 void OperationPrinter::printSuccessor(Block *successor) {
3729 printBlockName(successor);
3732 void OperationPrinter::printSuccessorAndUseList(Block *successor,
3733 ValueRange succOperands) {
3734 printBlockName(successor);
3735 if (succOperands.empty())
3739 interleaveComma(succOperands,
3740 [this](Value operand) { printValueID(operand); });
3742 interleaveComma(succOperands,
3743 [this](Value operand) { printType(operand.getType()); });
3747 void OperationPrinter::printRegion(Region ®ion, bool printEntryBlockArgs,
3748 bool printBlockTerminators,
3749 bool printEmptyBlock) {
3750 if (printerFlags.shouldSkipRegions()) {
3754 os << "{" << newLine;
3755 if (!region.empty()) {
3756 auto restoreDefaultDialect =
3757 llvm::make_scope_exit([&]() { defaultDialectStack.pop_back(); });
3758 if (auto iface = dyn_cast<OpAsmOpInterface>(region.getParentOp()))
3759 defaultDialectStack.push_back(iface.getDefaultDialect());
3761 defaultDialectStack.push_back("");
3763 auto *entryBlock = ®ion.front();
3764 // Force printing the block header if printEmptyBlock is set and the block
3765 // is empty or if printEntryBlockArgs is set and there are arguments to
3767 bool shouldAlwaysPrintBlockHeader =
3768 (printEmptyBlock && entryBlock->empty()) ||
3769 (printEntryBlockArgs && entryBlock->getNumArguments() != 0);
3770 print(entryBlock, shouldAlwaysPrintBlockHeader, printBlockTerminators);
3771 for (auto &b : llvm::drop_begin(region.getBlocks(), 1))
3774 os.indent(currentIndent) << "}";
3777 void OperationPrinter::printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3778 ValueRange operands) {
3780 os << "<<NULL AFFINE MAP>>";
3783 AffineMap map = mapAttr.getValue();
3784 unsigned numDims = map.getNumDims();
3785 auto printValueName = [&](unsigned pos, bool isSymbol) {
3786 unsigned index = isSymbol ? numDims + pos : pos;
3787 assert(index < operands.size());
3790 printValueID(operands[index]);
3795 interleaveComma(map.getResults(), [&](AffineExpr expr) {
3796 printAffineExpr(expr, printValueName);
3800 void OperationPrinter::printAffineExprOfSSAIds(AffineExpr expr,
3801 ValueRange dimOperands,
3802 ValueRange symOperands) {
3803 auto printValueName = [&](unsigned pos, bool isSymbol) {
3805 return printValueID(dimOperands[pos]);
3807 printValueID(symOperands[pos]);
3810 printAffineExpr(expr, printValueName);
3813 //===----------------------------------------------------------------------===//
3814 // print and dump methods
3815 //===----------------------------------------------------------------------===//
3817 void Attribute::print(raw_ostream &os, bool elideType) const {
3819 os << "<<NULL ATTRIBUTE>>";
3823 AsmState state(getContext());
3824 print(os, state, elideType);
3826 void Attribute::print(raw_ostream &os, AsmState &state, bool elideType) const {
3827 using AttrTypeElision = AsmPrinter::Impl::AttrTypeElision;
3828 AsmPrinter::Impl(os, state.getImpl())
3829 .printAttribute(*this, elideType ? AttrTypeElision::Must
3830 : AttrTypeElision::Never);
3833 void Attribute::dump() const {
3834 print(llvm::errs());
3835 llvm::errs() << "\n";
3838 void Attribute::printStripped(raw_ostream &os, AsmState &state) const {
3840 os << "<<NULL ATTRIBUTE>>";
3844 AsmPrinter::Impl subPrinter(os, state.getImpl());
3845 if (succeeded(subPrinter.printAlias(*this)))
3848 auto &dialect = this->getDialect();
3849 uint64_t posPrior = os.tell();
3850 DialectAsmPrinter printer(subPrinter);
3851 dialect.printAttribute(*this, printer);
3852 if (posPrior != os.tell())
3855 // Fallback to printing with prefix if the above failed to write anything
3856 // to the output stream.
3859 void Attribute::printStripped(raw_ostream &os) const {
3861 os << "<<NULL ATTRIBUTE>>";
3865 AsmState state(getContext());
3866 printStripped(os, state);
3869 void Type::print(raw_ostream &os) const {
3871 os << "<<NULL TYPE>>";
3875 AsmState state(getContext());
3878 void Type::print(raw_ostream &os, AsmState &state) const {
3879 AsmPrinter::Impl(os, state.getImpl()).printType(*this);
3882 void Type::dump() const {
3883 print(llvm::errs());
3884 llvm::errs() << "\n";
3887 void AffineMap::dump() const {
3888 print(llvm::errs());
3889 llvm::errs() << "\n";
3892 void IntegerSet::dump() const {
3893 print(llvm::errs());
3894 llvm::errs() << "\n";
3897 void AffineExpr::print(raw_ostream &os) const {
3899 os << "<<NULL AFFINE EXPR>>";
3902 AsmState state(getContext());
3903 AsmPrinter::Impl(os, state.getImpl()).printAffineExpr(*this);
3906 void AffineExpr::dump() const {
3907 print(llvm::errs());
3908 llvm::errs() << "\n";
3911 void AffineMap::print(raw_ostream &os) const {
3913 os << "<<NULL AFFINE MAP>>";
3916 AsmState state(getContext());
3917 AsmPrinter::Impl(os, state.getImpl()).printAffineMap(*this);
3920 void IntegerSet::print(raw_ostream &os) const {
3921 AsmState state(getContext());
3922 AsmPrinter::Impl(os, state.getImpl()).printIntegerSet(*this);
3925 void Value::print(raw_ostream &os) const { print(os, OpPrintingFlags()); }
3926 void Value::print(raw_ostream &os, const OpPrintingFlags &flags) const {
3928 os << "<<NULL VALUE>>";
3932 if (auto *op = getDefiningOp())
3933 return op->print(os, flags);
3934 // TODO: Improve BlockArgument print'ing.
3936 os <<
"<block argument> of type '" << arg.
getType()
3941 os <<
"<<NULL VALUE>>";
3945 if (
auto *op = getDefiningOp())
3946 return op->
print(os, state);
3950 os <<
"<block argument> of type '" << arg.
getType()
3955 print(llvm::errs());
3956 llvm::errs() <<
"\n";
3964 state.getImpl().getSSANameState().printValueID(*
this,
true,
3987 if (
auto result = llvm::dyn_cast<OpResult>(*
this)) {
3990 op = llvm::cast<BlockArgument>(*this).getOwner()->
getParentOp();
3992 os <<
"<<UNKNOWN SSA VALUE>>";
3998 printAsOperand(os, state);
4008 OperationPrinter printer(os, state.getImpl());
4009 if (!getParent() && !state.getPrinterFlags().shouldUseLocalScope()) {
4010 state.getImpl().initializeAliases(
this);
4011 printer.printTopLevelOperation(
this);
4013 printer.printFullOpWithIndentAndLoc(
this);
4019 llvm::errs() <<
"\n";
4024 llvm::errs() <<
"\n";
4030 os <<
"<<UNLINKED BLOCK>>\n";
4041 OperationPrinter(os, state.getImpl()).print(
this);
4050 os <<
"<<UNLINKED BLOCK>>\n";
4054 printAsOperand(os, state);
4057 OperationPrinter printer(os, state.getImpl());
4058 printer.printBlockName(
this);
4073 if (dimensions.empty())
4076 if (dimensions.empty())
4086 <<
"Failed parsing dimension list.";
4097 <<
"Failed parsing dimension list.";
4099 if (shapeArr.empty()) {
4101 <<
"Failed parsing dimension list. Did you mean an empty list? It "
4102 "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.
T findInstanceOf()
Return an instance of the given location type if one is nested under the current location.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
NamedAttribute represents a combination of a name and an Attribute value.
Attribute getValue() const
Return the value of the attribute.
virtual 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 shouldUseNameLocAsPrefix() const
Return if the printer should use NameLocs as prefixes when printing SSA IDs.
bool shouldAssumeVerified() const
Return if operation verification should be skipped.
OpPrintingFlags & 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()
LLVM_DUMP_METHOD void dumpPretty()
operand_range getOperands()
Returns an iterator on the underlying Value's.
user_range getUsers()
Returns a range of all users.
SuccessorRange getSuccessors()
result_range getResults()
unsigned getNumResults()
Return the number of results held by this operation.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
iterator_range< OpIterator > getOps()
Operation * getParentOp()
Return the parent operation this region is attached to.
unsigned getNumArguments()
BlockArgument getArgument(unsigned i)
This diagnostic handler is a simple RAII class that registers and erases a diagnostic handler on a gi...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
const void * getAsOpaquePointer() const
Methods for supporting PointerLikeTypeTraits.
Dialect & getDialect() const
Get the dialect this type is registered to.
static Type getFromOpaquePointer(const void *pointer)
void walkImmediateSubElements(function_ref< void(Attribute)> walkAttrsFn, function_ref< void(Type)> walkTypesFn) const
Walk all of the immediately nested sub-attributes and sub-types.
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
bool use_empty() const
Returns true if this value has no uses.
void print(raw_ostream &os) const
Type getType() const
Return the type of this value.
void printAsOperand(raw_ostream &os, AsmState &state) const
Print this value as if it were an operand.
user_range getUsers() const
Location getLoc() const
Return the location of this value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
void registerOperationLocation(Operation *op, unsigned line, unsigned col)
Register the location, line and column, within the buffer that the given operation was printed at.
const OpPrintingFlags & getPrinterFlags() const
Get the printer flags.
auto getResourcePrinters()
Return the non-dialect resource printers.
LogicalResult pushCyclicPrinting(const void *opaquePointer)
SSANameState & getSSANameState()
Get the state used for SSA names.
DialectInterfaceCollection< OpAsmDialectInterface > & getDialectInterfaces()
Return the dialects within the context that implement OpAsmDialectInterface.
AliasState & getAliasState()
Get the state used for aliases.
void initializeAliases(Operation *op)
Initialize the alias state to enable the printing of aliases.
AsmStateImpl(Operation *op, const OpPrintingFlags &printerFlags, AsmState::LocationMap *locationMap)
DenseMap< Dialect *, SetVector< AsmDialectResourceHandle > > & getDialectResources()
Return the referenced dialect resources within the printer.
AsmStateImpl(MLIRContext *ctx, const OpPrintingFlags &printerFlags, AsmState::LocationMap *locationMap)
DistinctState & getDistinctState()
Get the state used for distinct attribute identifiers.
Base class for DenseArrayAttr that is instantiated and specialized for each supported element type be...
static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef< T > content)
Builder from ArrayRef<T>.
void printType(Type type, AsmPrinter &printer)
Prints an LLVM Dialect type.
LogicalResult parseCommaSeparatedList(llvm::cl::Option &opt, StringRef argName, StringRef optionStr, function_ref< LogicalResult(StringRef)> elementParseFn)
Parse a string containing a list of comma-delimited elements, invoking the given parser for each sub-...
void printDimensionList(raw_ostream &stream, Range &&shape)
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
bool operator<(const Fraction &x, const Fraction &y)
Include the generated interface declarations.
ParseResult parseDimensionList(OpAsmParser &parser, DenseI64ArrayAttr &dimensions)
StringRef toString(AsmResourceEntryKind kind)
@ 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.