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/OpAsmOpInterface.cpp.inc"
129 #include "mlir/IR/OpAsmTypeInterface.cpp.inc"
133 return entry.
emitError() <<
"unknown 'resource' key '" << entry.
getKey()
134 <<
"' for dialect '" << getDialect()->getNamespace()
146 struct AsmPrinterOptions {
147 llvm::cl::opt<int64_t> printElementsAttrWithHexIfLarger{
148 "mlir-print-elementsattrs-with-hex-if-larger",
150 "Print DenseElementsAttrs with a hex string that have "
151 "more elements than the given upper limit (use -1 to disable)")};
153 llvm::cl::opt<unsigned> elideElementsAttrIfLarger{
154 "mlir-elide-elementsattrs-if-larger",
155 llvm::cl::desc(
"Elide ElementsAttrs with \"...\" that have "
156 "more elements than the given upper limit")};
158 llvm::cl::opt<unsigned> elideResourceStringsIfLarger{
159 "mlir-elide-resource-strings-if-larger",
161 "Elide printing value of resources if string is too long in chars.")};
163 llvm::cl::opt<bool> printDebugInfoOpt{
164 "mlir-print-debuginfo", llvm::cl::init(
false),
165 llvm::cl::desc(
"Print debug info in MLIR output")};
167 llvm::cl::opt<bool> printPrettyDebugInfoOpt{
168 "mlir-pretty-debuginfo", llvm::cl::init(
false),
169 llvm::cl::desc(
"Print pretty debug info in MLIR output")};
173 llvm::cl::opt<bool> printGenericOpFormOpt{
174 "mlir-print-op-generic", llvm::cl::init(
false),
175 llvm::cl::desc(
"Print the generic op form"), llvm::cl::Hidden};
177 llvm::cl::opt<bool> assumeVerifiedOpt{
178 "mlir-print-assume-verified", llvm::cl::init(
false),
179 llvm::cl::desc(
"Skip op verification when using custom printers"),
182 llvm::cl::opt<bool> printLocalScopeOpt{
183 "mlir-print-local-scope", llvm::cl::init(
false),
184 llvm::cl::desc(
"Print with local scope and inline information (eliding "
185 "aliases for attributes, types, and locations)")};
187 llvm::cl::opt<bool> skipRegionsOpt{
188 "mlir-print-skip-regions", llvm::cl::init(
false),
189 llvm::cl::desc(
"Skip regions when printing ops.")};
191 llvm::cl::opt<bool> printValueUsers{
192 "mlir-print-value-users", llvm::cl::init(
false),
194 "Print users of operation results and block arguments as a comment")};
196 llvm::cl::opt<bool> printUniqueSSAIDs{
197 "mlir-print-unique-ssa-ids", llvm::cl::init(
false),
198 llvm::cl::desc(
"Print unique SSA ID numbers for values, block arguments "
199 "and naming conflicts across all regions")};
201 llvm::cl::opt<bool> useNameLocAsPrefix{
202 "mlir-use-nameloc-as-prefix", llvm::cl::init(
false),
203 llvm::cl::desc(
"Print SSA IDs using NameLocs as prefixes")};
207 static llvm::ManagedStatic<AsmPrinterOptions>
clOptions;
218 : printDebugInfoFlag(false), printDebugInfoPrettyFormFlag(false),
219 printGenericOpFormFlag(false), skipRegionsFlag(false),
220 assumeVerifiedFlag(false), printLocalScope(false),
221 printValueUsersFlag(false), printUniqueSSAIDsFlag(false),
222 useNameLocAsPrefix(false) {
226 if (
clOptions->elideElementsAttrIfLarger.getNumOccurrences())
227 elementsAttrElementLimit =
clOptions->elideElementsAttrIfLarger;
228 if (
clOptions->printElementsAttrWithHexIfLarger.getNumOccurrences())
229 elementsAttrHexElementLimit =
230 clOptions->printElementsAttrWithHexIfLarger.getValue();
231 if (
clOptions->elideResourceStringsIfLarger.getNumOccurrences())
232 resourceStringCharLimit =
clOptions->elideResourceStringsIfLarger;
233 printDebugInfoFlag =
clOptions->printDebugInfoOpt;
234 printDebugInfoPrettyFormFlag =
clOptions->printPrettyDebugInfoOpt;
235 printGenericOpFormFlag =
clOptions->printGenericOpFormOpt;
236 assumeVerifiedFlag =
clOptions->assumeVerifiedOpt;
237 printLocalScope =
clOptions->printLocalScopeOpt;
238 skipRegionsFlag =
clOptions->skipRegionsOpt;
239 printValueUsersFlag =
clOptions->printValueUsers;
240 printUniqueSSAIDsFlag =
clOptions->printUniqueSSAIDs;
241 useNameLocAsPrefix =
clOptions->useNameLocAsPrefix;
250 elementsAttrElementLimit = largeElementLimit;
256 elementsAttrHexElementLimit = largeElementLimit;
262 resourceStringCharLimit = largeResourceLimit;
270 printDebugInfoFlag = enable;
271 printDebugInfoPrettyFormFlag = prettyForm;
277 printGenericOpFormFlag = enable;
283 skipRegionsFlag = skip;
289 assumeVerifiedFlag = enable;
297 printLocalScope = enable;
303 printValueUsersFlag = enable;
310 printUniqueSSAIDsFlag = enable;
316 return elementsAttrElementLimit &&
317 *elementsAttrElementLimit < int64_t(attr.getNumElements()) &&
318 !llvm::isa<SplatElementsAttr>(attr);
324 return (elementsAttrHexElementLimit != -1) &&
325 (elementsAttrHexElementLimit < int64_t(attr.getNumElements())) &&
326 !llvm::isa<SplatElementsAttr>(attr);
331 return elementsAttrElementLimit;
336 return elementsAttrHexElementLimit;
341 return resourceStringCharLimit;
346 return printDebugInfoFlag;
351 return printDebugInfoPrettyFormFlag;
356 return printGenericOpFormFlag;
364 return assumeVerifiedFlag;
372 return printValueUsersFlag;
382 return useNameLocAsPrefix;
393 struct NewLineCounter {
394 unsigned curLine = 1;
397 static raw_ostream &
operator<<(raw_ostream &os, NewLineCounter &newLine) {
416 template <
typename Container,
typename UnaryFunctor>
418 llvm::interleaveComma(c,
os, eachFn);
464 function_ref<
void(
unsigned,
bool)> printValueName =
nullptr);
477 bool withKeyword =
false);
481 bool isTopLevel =
false);
517 function_ref<
void(
unsigned,
bool)> printValueName =
nullptr);
541 SymbolAlias(StringRef name, uint32_t suffixIndex,
bool isType,
543 : name(name), suffixIndex(suffixIndex), isType(isType),
544 isDeferrable(isDeferrable) {}
547 void print(raw_ostream &os)
const {
548 os << (isType ?
"!" :
"#") << name;
554 bool isTypeAlias()
const {
return isType; }
557 bool canBeDeferred()
const {
return isDeferrable; }
563 uint32_t suffixIndex : 30;
567 bool isDeferrable : 1;
571 bool isPrinted =
false;
577 class AliasInitializer {
581 llvm::BumpPtrAllocator &aliasAllocator)
582 : interfaces(interfaces), aliasAllocator(aliasAllocator),
583 aliasOS(aliasBuffer) {}
586 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias);
594 std::pair<size_t, size_t>
visit(
Attribute attr,
bool canBeDeferred =
false,
595 bool elideType =
false) {
596 return visitImpl(attr, aliases, canBeDeferred, elideType);
603 std::pair<size_t, size_t>
visit(
Type type,
bool canBeDeferred =
false) {
604 return visitImpl(type, aliases, canBeDeferred);
608 struct InProgressAliasInfo {
609 InProgressAliasInfo()
610 : aliasDepth(0), isType(false), canBeDeferred(false) {}
611 InProgressAliasInfo(StringRef alias)
612 : alias(alias), aliasDepth(1), isType(false), canBeDeferred(false) {}
614 bool operator<(
const InProgressAliasInfo &rhs)
const {
616 if (aliasDepth != rhs.aliasDepth)
617 return aliasDepth < rhs.aliasDepth;
618 if (isType != rhs.isType)
620 return alias < rhs.alias;
625 std::optional<StringRef> alias;
628 unsigned aliasDepth : 30;
632 bool canBeDeferred : 1;
642 template <
typename T,
typename... PrintArgs>
643 std::pair<size_t, size_t>
645 llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
646 bool canBeDeferred, PrintArgs &&...printArgs);
649 void markAliasNonDeferrable(
size_t aliasIndex);
653 template <
typename T>
654 void generateAlias(T symbol, InProgressAliasInfo &alias,
bool canBeDeferred);
658 static void initializeAliases(
659 llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
660 llvm::MapVector<const void *, SymbolAlias> &symbolToAlias);
666 llvm::BumpPtrAllocator &aliasAllocator;
669 llvm::MapVector<const void *, InProgressAliasInfo> aliases;
673 llvm::raw_svector_ostream aliasOS;
681 class DummyAliasOperationPrinter :
private OpAsmPrinter {
683 explicit DummyAliasOperationPrinter(
const OpPrintingFlags &printerFlags,
684 AliasInitializer &initializer)
685 : printerFlags(printerFlags), initializer(initializer) {}
689 void printCustomOrGenericOp(
Operation *op)
override {
691 if (printerFlags.shouldPrintDebugInfo())
692 initializer.visit(op->
getLoc(),
true);
695 if (!printerFlags.shouldPrintGenericOpForm()) {
706 void printGenericOp(
Operation *op,
bool printOpName =
true)
override {
708 if (!printerFlags.shouldSkipRegions()) {
722 printAttribute(attr.getValue());
728 void print(
Block *block,
bool printBlockArgs =
true,
729 bool printBlockTerminator =
true) {
732 if (printBlockArgs) {
737 if (printerFlags.shouldPrintDebugInfo())
739 initializer.visit(arg.getLoc(),
false);
747 auto range = llvm::make_range(
749 std::prev(block->
end(),
750 (!hasTerminator || printBlockTerminator) ? 0 : 1));
752 printCustomOrGenericOp(&op);
757 bool printBlockTerminators,
758 bool printEmptyBlock =
false)
override {
761 if (printerFlags.shouldSkipRegions()) {
766 auto *entryBlock = ®ion.
front();
767 print(entryBlock, printEntryBlockArgs, printBlockTerminators);
768 for (
Block &b : llvm::drop_begin(region, 1))
773 bool omitType)
override {
776 if (printerFlags.shouldPrintDebugInfo())
778 initializer.visit(arg.
getLoc(),
false);
782 void printType(
Type type)
override { initializer.visit(type); }
785 void printAttribute(
Attribute attr)
override { initializer.visit(attr); }
786 void printAttributeWithoutType(
Attribute attr)
override {
787 printAttribute(attr);
789 LogicalResult printAlias(
Attribute attr)
override {
790 initializer.visit(attr);
793 LogicalResult printAlias(
Type type)
override {
794 initializer.visit(type);
799 void printOptionalLocationSpecifier(
Location loc)
override {
809 if (elidedAttrs.empty()) {
811 printAttribute(attr.getValue());
814 llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
817 if (!elidedAttrsSet.contains(attr.getName().strref()))
818 printAttribute(attr.getValue());
820 void printOptionalAttrDictWithKeyword(
823 printOptionalAttrDict(attrs, elidedAttrs);
828 raw_ostream &getStream()
const override {
return os; }
832 void printFloat(
const APFloat &)
override {}
833 void printAffineMapOfSSAIds(AffineMapAttr,
ValueRange)
override {}
836 void increaseIndent()
override {}
837 void decreaseIndent()
override {}
838 void printOperand(
Value)
override {}
839 void printOperand(
Value, raw_ostream &os)
override {
848 void printSymbolName(StringRef)
override {}
849 void printSuccessor(
Block *)
override {}
857 AliasInitializer &initializer;
860 mutable llvm::raw_null_ostream os;
865 explicit DummyAliasDialectAsmPrinter(AliasInitializer &initializer,
868 : initializer(initializer), canBeDeferred(canBeDeferred),
869 childIndices(childIndices) {}
874 template <
typename T,
typename... PrintArgs>
875 size_t printAndVisitNestedAliases(T value, PrintArgs &&...printArgs) {
876 printAndVisitNestedAliasesImpl(value, printArgs...);
877 return maxAliasDepth;
883 void printAndVisitNestedAliasesImpl(
Attribute attr,
bool elideType) {
884 if (!isa<BuiltinDialect>(attr.
getDialect())) {
888 }
else if (llvm::isa<AffineMapAttr, DenseArrayAttr, FloatAttr, IntegerAttr,
889 IntegerSetAttr, UnitAttr>(attr)) {
891 }
else if (
auto distinctAttr = dyn_cast<DistinctAttr>(attr)) {
892 printAttribute(distinctAttr.getReferencedAttr());
893 }
else if (
auto dictAttr = dyn_cast<DictionaryAttr>(attr)) {
895 printAttribute(nestedAttr.getName());
896 printAttribute(nestedAttr.getValue());
898 }
else if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr)) {
899 for (
Attribute nestedAttr : arrayAttr.getValue())
900 printAttribute(nestedAttr);
901 }
else if (
auto typeAttr = dyn_cast<TypeAttr>(attr)) {
903 }
else if (
auto locAttr = dyn_cast<OpaqueLoc>(attr)) {
904 printAttribute(locAttr.getFallbackLocation());
905 }
else if (
auto locAttr = dyn_cast<NameLoc>(attr)) {
906 if (!isa<UnknownLoc>(locAttr.getChildLoc()))
907 printAttribute(locAttr.getChildLoc());
908 }
else if (
auto locAttr = dyn_cast<CallSiteLoc>(attr)) {
909 printAttribute(locAttr.getCallee());
910 printAttribute(locAttr.getCaller());
911 }
else if (
auto locAttr = dyn_cast<FusedLoc>(attr)) {
912 if (
Attribute metadata = locAttr.getMetadata())
913 printAttribute(metadata);
914 for (
Location nestedLoc : locAttr.getLocations())
915 printAttribute(nestedLoc);
920 if (
auto typedAttr = llvm::dyn_cast<TypedAttr>(attr)) {
921 Type attrType = typedAttr.getType();
922 if (!llvm::isa<NoneType>(attrType))
927 void printAndVisitNestedAliasesImpl(
Type type) {
932 if (
auto memrefTy = llvm::dyn_cast<MemRefType>(type)) {
934 MemRefLayoutAttrInterface layout = memrefTy.getLayout();
935 if (!llvm::isa<AffineMapAttr>(layout) || !layout.isIdentity())
936 printAttribute(memrefTy.getLayout());
937 if (memrefTy.getMemorySpace())
938 printAttribute(memrefTy.getMemorySpace());
943 auto visitFn = [&](
auto element) {
945 (void)printAlias(element);
952 recordAliasResult(initializer.visit(type, canBeDeferred));
956 void printAttribute(
Attribute attr)
override {
957 recordAliasResult(initializer.visit(attr, canBeDeferred));
959 void printAttributeWithoutType(
Attribute attr)
override {
961 initializer.visit(attr, canBeDeferred,
true));
963 LogicalResult printAlias(
Attribute attr)
override {
964 printAttribute(attr);
967 LogicalResult printAlias(
Type type)
override {
973 void recordAliasResult(std::pair<size_t, size_t> aliasDepthAndIndex) {
974 childIndices.push_back(aliasDepthAndIndex.second);
975 if (aliasDepthAndIndex.first > maxAliasDepth)
976 maxAliasDepth = aliasDepthAndIndex.first;
981 raw_ostream &getStream()
const override {
return os; }
985 void printFloat(
const APFloat &)
override {}
988 void printSymbolName(StringRef)
override {}
991 LogicalResult pushCyclicPrinting(
const void *opaquePointer)
override {
992 return success(cyclicPrintingStack.insert(opaquePointer));
995 void popCyclicPrinting()
override { cyclicPrintingStack.pop_back(); }
1002 AliasInitializer &initializer;
1011 size_t maxAliasDepth = 0;
1014 mutable llvm::raw_null_ostream os;
1022 StringRef allowedPunctChars =
"$._-",
1023 bool allowTrailingDigit =
true) {
1024 assert(!name.empty() &&
"Shouldn't have an empty name here");
1026 auto validChar = [&](
char ch) {
1027 return llvm::isAlnum(ch) || allowedPunctChars.contains(ch);
1030 auto copyNameToBuffer = [&] {
1031 for (
char ch : name) {
1033 buffer.push_back(ch);
1035 buffer.push_back(
'_');
1037 buffer.append(llvm::utohexstr((
unsigned char)ch));
1044 if (isdigit(name[0]) || (!validChar(name[0]) && name[0] !=
' ')) {
1045 buffer.push_back(
'_');
1052 if (!allowTrailingDigit && isdigit(name.back())) {
1054 buffer.push_back(
'_');
1059 for (
char ch : name) {
1060 if (!validChar(ch)) {
1072 void AliasInitializer::initializeAliases(
1073 llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
1074 llvm::MapVector<const void *, SymbolAlias> &symbolToAlias) {
1076 unprocessedAliases = visitedSymbols.takeVector();
1077 llvm::stable_sort(unprocessedAliases, [](
const auto &lhs,
const auto &rhs) {
1078 return lhs.second < rhs.second;
1081 llvm::StringMap<unsigned> nameCounts;
1082 for (
auto &[symbol, aliasInfo] : unprocessedAliases) {
1083 if (!aliasInfo.alias)
1085 StringRef alias = *aliasInfo.alias;
1086 unsigned nameIndex = nameCounts[alias]++;
1087 symbolToAlias.insert(
1088 {symbol, SymbolAlias(alias, nameIndex, aliasInfo.isType,
1089 aliasInfo.canBeDeferred)});
1093 void AliasInitializer::initialize(
1095 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias) {
1099 DummyAliasOperationPrinter aliasPrinter(printerFlags, *
this);
1100 aliasPrinter.printCustomOrGenericOp(op);
1103 initializeAliases(aliases, attrTypeToAlias);
1106 template <
typename T,
typename... PrintArgs>
1107 std::pair<size_t, size_t> AliasInitializer::visitImpl(
1108 T value, llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
1109 bool canBeDeferred, PrintArgs &&...printArgs) {
1110 auto [it, inserted] =
1111 aliases.insert({value.getAsOpaquePointer(), InProgressAliasInfo()});
1112 size_t aliasIndex = std::distance(aliases.begin(), it);
1116 markAliasNonDeferrable(aliasIndex);
1117 return {
static_cast<size_t>(it->second.aliasDepth), aliasIndex};
1121 generateAlias(value, it->second, canBeDeferred);
1122 it->second.isType = std::is_base_of_v<Type, T>;
1123 it->second.canBeDeferred = canBeDeferred;
1127 DummyAliasDialectAsmPrinter printer(*
this, canBeDeferred, childAliases);
1128 size_t maxAliasDepth =
1129 printer.printAndVisitNestedAliases(value, printArgs...);
1132 it = std::next(aliases.begin(), aliasIndex);
1135 it->second.childIndices = std::move(childAliases);
1137 it->second.aliasDepth = maxAliasDepth + 1;
1140 return {(size_t)it->second.aliasDepth, aliasIndex};
1143 void AliasInitializer::markAliasNonDeferrable(
size_t aliasIndex) {
1144 auto *it = std::next(aliases.begin(), aliasIndex);
1148 if (!it->second.canBeDeferred)
1151 it->second.canBeDeferred =
false;
1154 for (
size_t childIndex : it->second.childIndices)
1155 markAliasNonDeferrable(childIndex);
1158 template <
typename T>
1159 void AliasInitializer::generateAlias(T symbol, InProgressAliasInfo &alias,
1160 bool canBeDeferred) {
1162 for (
const auto &interface : interfaces) {
1164 interface.getAlias(symbol, aliasOS);
1167 nameBuffer = std::move(aliasBuffer);
1168 assert(!nameBuffer.empty() &&
"expected valid alias name");
1173 if (nameBuffer.empty())
1180 name = name.copy(aliasAllocator);
1181 alias = InProgressAliasInfo(name);
1199 LogicalResult getAlias(
Attribute attr, raw_ostream &os)
const;
1203 LogicalResult getAlias(
Type ty, raw_ostream &os)
const;
1207 void printNonDeferredAliases(
AsmPrinter::Impl &p, NewLineCounter &newLine) {
1208 printAliases(p, newLine,
false);
1213 printAliases(p, newLine,
true);
1223 llvm::MapVector<const void *, SymbolAlias> attrTypeToAlias;
1226 llvm::BumpPtrAllocator aliasAllocator;
1230 void AliasState::initialize(
1233 AliasInitializer initializer(interfaces, aliasAllocator);
1234 initializer.initialize(op, printerFlags, attrTypeToAlias);
1237 LogicalResult AliasState::getAlias(
Attribute attr, raw_ostream &os)
const {
1239 if (it == attrTypeToAlias.end())
1241 it->second.print(os);
1245 LogicalResult AliasState::getAlias(
Type ty, raw_ostream &os)
const {
1247 if (it == attrTypeToAlias.end())
1249 if (!it->second.isPrinted)
1252 it->second.print(os);
1256 void AliasState::printAliases(
AsmPrinter::Impl &p, NewLineCounter &newLine,
1258 auto filterFn = [=](
const auto &aliasIt) {
1259 return aliasIt.second.canBeDeferred() == isDeferred;
1261 for (
auto &[opaqueSymbol, alias] :
1262 llvm::make_filter_range(attrTypeToAlias, filterFn)) {
1266 if (alias.isTypeAlias()) {
1269 alias.isPrinted =
true;
1296 class SSANameState {
1299 enum :
unsigned { NameSentinel = ~0U };
1302 SSANameState() =
default;
1307 void printValueID(
Value value,
bool printResultNo, raw_ostream &stream)
const;
1310 void printOperationID(
Operation *op, raw_ostream &stream)
const;
1317 BlockInfo getBlockInfo(
Block *block);
1326 void numberValuesInRegion(
Region ®ion);
1327 void numberValuesInBlock(
Block &block);
1334 void getResultIDAndNumber(
OpResult result,
Value &lookupValue,
1335 std::optional<int> &lookupResultNo)
const;
1338 void setValueName(
Value value, StringRef name);
1342 StringRef uniqueValueName(StringRef name);
1365 llvm::ScopedHashTable<StringRef, char> usedNames;
1366 llvm::BumpPtrAllocator usedNameAllocator;
1369 unsigned nextValueID = 0;
1371 unsigned nextArgumentID = 0;
1373 unsigned nextConflictID = 0;
1382 : printerFlags(printerFlags) {
1383 llvm::SaveAndRestore valueIDSaver(nextValueID);
1384 llvm::SaveAndRestore argumentIDSaver(nextArgumentID);
1385 llvm::SaveAndRestore conflictIDSaver(nextConflictID);
1390 using UsedNamesScopeTy = llvm::ScopedHashTable<StringRef, char>::ScopeTy;
1391 using NamingContext =
1392 std::tuple<Region *, unsigned, unsigned, unsigned, UsedNamesScopeTy *>;
1395 llvm::BumpPtrAllocator allocator;
1398 auto *topLevelNamesScope =
1399 new (allocator.Allocate<UsedNamesScopeTy>()) UsedNamesScopeTy(usedNames);
1403 nameContext.push_back(std::make_tuple(®ion, nextValueID, nextArgumentID,
1404 nextConflictID, topLevelNamesScope));
1406 numberValuesInOp(*op);
1408 while (!nameContext.empty()) {
1410 UsedNamesScopeTy *parentScope;
1414 std::tie(region, std::ignore, std::ignore, std::ignore, parentScope) =
1415 nameContext.pop_back_val();
1417 std::tie(region, nextValueID, nextArgumentID, nextConflictID,
1418 parentScope) = nameContext.pop_back_val();
1422 while (usedNames.getCurScope() != parentScope) {
1423 usedNames.getCurScope()->~UsedNamesScopeTy();
1424 assert((usedNames.getCurScope() !=
nullptr || parentScope ==
nullptr) &&
1425 "top level parentScope must be a nullptr");
1429 auto *curNamesScope =
new (allocator.Allocate<UsedNamesScopeTy>())
1430 UsedNamesScopeTy(usedNames);
1432 numberValuesInRegion(*region);
1436 nameContext.push_back(std::make_tuple(®ion, nextValueID,
1437 nextArgumentID, nextConflictID,
1442 while (usedNames.getCurScope() !=
nullptr)
1443 usedNames.getCurScope()->~UsedNamesScopeTy();
1446 void SSANameState::printValueID(
Value value,
bool printResultNo,
1447 raw_ostream &stream)
const {
1449 stream <<
"<<NULL VALUE>>";
1453 std::optional<int> resultNo;
1454 auto lookupValue = value;
1458 if (
OpResult result = dyn_cast<OpResult>(value))
1459 getResultIDAndNumber(result, lookupValue, resultNo);
1461 auto it = valueIDs.find(lookupValue);
1462 if (it == valueIDs.end()) {
1463 stream <<
"<<UNKNOWN SSA VALUE>>";
1468 if (it->second != NameSentinel) {
1469 stream << it->second;
1471 auto nameIt = valueNames.find(lookupValue);
1472 assert(nameIt != valueNames.end() &&
"Didn't have a name entry?");
1473 stream << nameIt->second;
1476 if (resultNo && printResultNo)
1477 stream <<
'#' << *resultNo;
1480 void SSANameState::printOperationID(
Operation *op, raw_ostream &stream)
const {
1481 auto it = operationIDs.find(op);
1482 if (it == operationIDs.end()) {
1483 stream <<
"<<UNKNOWN OPERATION>>";
1485 stream <<
'%' << it->second;
1490 auto it = opResultGroups.find(op);
1491 return it == opResultGroups.end() ?
ArrayRef<int>() : it->second;
1494 BlockInfo SSANameState::getBlockInfo(
Block *block) {
1495 auto it = blockNames.find(block);
1496 BlockInfo invalidBlock{-1,
"INVALIDBLOCK"};
1497 return it != blockNames.end() ? it->second : invalidBlock;
1500 void SSANameState::shadowRegionArgs(
Region ®ion,
ValueRange namesToUse) {
1501 assert(!region.
empty() &&
"cannot shadow arguments of an empty region");
1503 "incorrect number of names passed in");
1505 "only KnownIsolatedFromAbove ops can shadow names");
1508 for (
unsigned i = 0, e = namesToUse.size(); i != e; ++i) {
1509 auto nameToUse = namesToUse[i];
1510 if (nameToUse ==
nullptr)
1515 llvm::raw_svector_ostream nameStream(nameStr);
1516 printValueID(nameToUse,
true, nameStream);
1519 assert(valueIDs[nameToReplace] == NameSentinel);
1522 auto name = StringRef(nameStream.str()).drop_front();
1525 valueNames[nameToReplace] = name.copy(usedNameAllocator);
1531 StringRef maybeGetValueNameFromLoc(
Value value, StringRef name) {
1533 return maybeNameLoc.getName();
1538 void SSANameState::numberValuesInRegion(
Region ®ion) {
1539 auto setBlockArgNameFn = [&](
Value arg, StringRef name) {
1540 assert(!valueIDs.count(arg) &&
"arg numbered multiple times");
1541 assert(llvm::cast<BlockArgument>(arg).getOwner()->getParent() == ®ion &&
1542 "arg not defined in current region");
1544 name = maybeGetValueNameFromLoc(arg, name);
1545 setValueName(arg, name);
1550 if (
auto asmInterface = dyn_cast<OpAsmOpInterface>(op))
1551 asmInterface.getAsmBlockArgumentNames(region, setBlockArgNameFn);
1556 unsigned nextBlockID = 0;
1557 for (
auto &block : region) {
1560 auto blockInfoIt = blockNames.insert({&block, {-1,
""}});
1561 if (blockInfoIt.second) {
1565 llvm::raw_string_ostream(name) <<
"^bb" << nextBlockID;
1566 blockInfoIt.first->second.name = StringRef(name).copy(usedNameAllocator);
1568 blockInfoIt.first->second.ordering = nextBlockID++;
1570 numberValuesInBlock(block);
1574 void SSANameState::numberValuesInBlock(
Block &block) {
1579 llvm::raw_svector_ostream specialName(specialNameBuffer);
1581 if (valueIDs.count(arg))
1584 specialNameBuffer.resize(strlen(
"arg"));
1585 specialName << nextArgumentID++;
1587 StringRef specialNameStr = specialName.str();
1589 specialNameStr = maybeGetValueNameFromLoc(arg, specialNameStr);
1590 setValueName(arg, specialNameStr);
1594 for (
auto &op : block)
1595 numberValuesInOp(op);
1598 void SSANameState::numberValuesInOp(
Operation &op) {
1601 auto setResultNameFn = [&](
Value result, StringRef name) {
1602 assert(!valueIDs.count(result) &&
"result numbered multiple times");
1603 assert(result.
getDefiningOp() == &op &&
"result not defined by 'op'");
1605 name = maybeGetValueNameFromLoc(result, name);
1606 setValueName(result, name);
1609 if (
int resultNo = llvm::cast<OpResult>(result).getResultNumber())
1610 resultGroups.push_back(resultNo);
1613 auto setBlockNameFn = [&](
Block *block, StringRef name) {
1615 "getAsmBlockArgumentNames callback invoked on a block not directly "
1616 "nested under the current operation");
1617 assert(!blockNames.count(block) &&
"block numbered multiple times");
1620 if (name.data() != tmpBuffer.data()) {
1621 tmpBuffer.append(name);
1622 name = tmpBuffer.str();
1624 name = name.copy(usedNameAllocator);
1625 blockNames[block] = {-1, name};
1629 if (OpAsmOpInterface asmInterface = dyn_cast<OpAsmOpInterface>(&op)) {
1630 asmInterface.getAsmBlockNames(setBlockNameFn);
1631 asmInterface.getAsmResultNames(setResultNameFn);
1636 if (numResults == 0) {
1639 if (operationIDs.try_emplace(&op, nextValueID).second)
1648 setValueName(resultBegin, nameLoc.getName());
1653 if (valueIDs.try_emplace(resultBegin, nextValueID).second)
1657 if (resultGroups.size() != 1) {
1658 llvm::array_pod_sort(resultGroups.begin(), resultGroups.end());
1659 opResultGroups.try_emplace(&op, std::move(resultGroups));
1663 void SSANameState::getResultIDAndNumber(
1665 std::optional<int> &lookupResultNo)
const {
1673 auto resultGroupIt = opResultGroups.find(owner);
1674 if (resultGroupIt == opResultGroups.end()) {
1676 lookupResultNo = resultNo;
1683 const auto *it = llvm::upper_bound(resultGroups, resultNo);
1684 int groupResultNo = 0, groupSize = 0;
1687 if (it == resultGroups.end()) {
1688 groupResultNo = resultGroups.back();
1689 groupSize =
static_cast<int>(owner->
getNumResults()) - resultGroups.back();
1692 groupResultNo = *std::prev(it);
1693 groupSize = *it - groupResultNo;
1698 lookupResultNo = resultNo - groupResultNo;
1699 lookupValue = owner->
getResult(groupResultNo);
1702 void SSANameState::setValueName(
Value value, StringRef name) {
1705 valueIDs[value] = nextValueID++;
1709 valueIDs[value] = NameSentinel;
1710 valueNames[value] = uniqueValueName(name);
1713 StringRef SSANameState::uniqueValueName(StringRef name) {
1718 if (!usedNames.count(name)) {
1719 name = name.copy(usedNameAllocator);
1725 probeName.push_back(
'_');
1727 probeName += llvm::utostr(nextConflictID++);
1728 if (!usedNames.count(probeName)) {
1729 name = probeName.str().copy(usedNameAllocator);
1732 probeName.resize(name.size() + 1);
1736 usedNames.insert(name,
char());
1746 class DistinctState {
1752 uint64_t distinctCounter = 0;
1757 uint64_t DistinctState::getId(
DistinctAttr distinctAttr) {
1758 auto [it, inserted] =
1759 distinctAttrMap.try_emplace(distinctAttr, distinctCounter);
1762 return it->getSecond();
1769 AsmParsedResourceEntry::~AsmParsedResourceEntry() =
default;
1770 AsmResourceBuilder::~AsmResourceBuilder() =
default;
1771 AsmResourceParser::~AsmResourceParser() =
default;
1772 AsmResourcePrinter::~AsmResourcePrinter() =
default;
1776 case AsmResourceEntryKind::Blob:
1778 case AsmResourceEntryKind::Bool:
1780 case AsmResourceEntryKind::String:
1783 llvm_unreachable(
"unknown AsmResourceEntryKind");
1787 std::unique_ptr<ResourceCollection> &collection = keyToResources[key.str()];
1789 collection = std::make_unique<ResourceCollection>(key);
1793 std::vector<std::unique_ptr<AsmResourcePrinter>>
1795 std::vector<std::unique_ptr<AsmResourcePrinter>> printers;
1796 for (
auto &it : keyToResources) {
1797 ResourceCollection *collection = it.second.get();
1799 return collection->buildResources(op, builder);
1801 printers.emplace_back(
1807 LogicalResult FallbackAsmResourceMap::ResourceCollection::parseResource(
1811 FailureOr<AsmResourceBlob> blob = entry.
parseAsBlob();
1814 resources.emplace_back(entry.
getKey(), std::move(*blob));
1821 resources.emplace_back(entry.
getKey(), *value);
1828 resources.emplace_back(entry.
getKey(), std::move(*str));
1835 void FallbackAsmResourceMap::ResourceCollection::buildResources(
1837 for (
const auto &entry : resources) {
1838 if (
const auto *value = std::get_if<AsmResourceBlob>(&entry.value))
1840 else if (
const auto *value = std::get_if<bool>(&entry.value))
1842 else if (
const auto *value = std::get_if<std::string>(&entry.value))
1845 llvm_unreachable(
"unknown AsmResourceEntryKind");
1859 : interfaces(op->
getContext()), nameState(op, printerFlags),
1860 printerFlags(printerFlags), locationMap(locationMap) {}
1863 : interfaces(ctx), printerFlags(printerFlags), locationMap(locationMap) {}
1867 aliasState.initialize(op, printerFlags, interfaces);
1887 return llvm::make_pointee_range(externalResourcePrinters);
1897 (*locationMap)[op] = std::make_pair(line, col);
1903 return dialectResources;
1907 return success(cyclicPrintingStack.insert(opaquePointer));
1923 AliasState aliasState;
1926 SSANameState nameState;
1929 DistinctState distinctState;
1945 template <
typename Range>
1949 [&stream](
const auto &dimSize) {
1950 if (ShapedType::isDynamic(dimSize))
1968 return printerFlags;
1972 auto parentThreadId = llvm::get_threadid();
1974 if (parentThreadId == llvm::get_threadid()) {
1976 diag.print(llvm::dbgs());
1977 llvm::dbgs() <<
"\n";
1983 if (failed(
verify(op))) {
1984 LLVM_DEBUG(llvm::dbgs()
1986 <<
"' failed to verify and will be printed in generic form\n");
1990 return printerFlags;
2009 return impl->getPrinterFlags();
2013 std::unique_ptr<AsmResourcePrinter> printer) {
2014 impl->externalResourcePrinters.emplace_back(std::move(printer));
2019 return impl->getDialectResources();
2027 : os(os), state(state), printerFlags(state.getPrinterFlags()) {}
2035 printLocation(loc, allowAlias);
2041 if (!isTopLevel && succeeded(state.getAliasState().getAlias(loc, os)))
2045 .Case<OpaqueLoc>([&](OpaqueLoc loc) {
2046 printLocationInternal(loc.getFallbackLocation(), pretty);
2048 .Case<UnknownLoc>([&](UnknownLoc loc) {
2056 os << loc.getFilename().getValue();
2058 printEscapedString(loc.getFilename());
2059 if (loc.getEndColumn() == loc.getStartColumn() &&
2060 loc.getStartLine() == loc.getEndLine()) {
2061 os <<
':' << loc.getStartLine() <<
':' << loc.getStartColumn();
2064 if (loc.getStartLine() == loc.getEndLine()) {
2065 os <<
':' << loc.getStartLine() <<
':' << loc.getStartColumn()
2066 <<
" to :" << loc.getEndColumn();
2069 os <<
':' << loc.getStartLine() <<
':' << loc.getStartColumn() <<
" to "
2070 << loc.getEndLine() <<
':' << loc.getEndColumn();
2072 .Case<NameLoc>([&](NameLoc loc) {
2073 printEscapedString(loc.getName());
2076 auto childLoc = loc.getChildLoc();
2077 if (!llvm::isa<UnknownLoc>(childLoc)) {
2079 printLocationInternal(childLoc, pretty);
2083 .Case<CallSiteLoc>([&](CallSiteLoc loc) {
2088 printLocationInternal(callee, pretty);
2090 if (llvm::isa<NameLoc>(callee)) {
2091 if (llvm::isa<FileLineColLoc>(caller)) {
2094 os << newLine <<
" at ";
2097 os << newLine <<
" at ";
2102 printLocationInternal(caller, pretty);
2106 .Case<FusedLoc>([&](
FusedLoc loc) {
2109 if (
Attribute metadata = loc.getMetadata()) {
2117 [&](Location loc) { printLocationInternal(loc, pretty); },
2118 [&]() { os << ", "; });
2121 .Default([&](LocationAttr loc) {
2122 // Assumes that this is a dialect-specific attribute and prints it
2124 printAttribute(loc);
2130 static void printFloatValue(const APFloat &apValue, raw_ostream &os,
2131 bool *printedHex = nullptr) {
2132 // We would like to output the FP constant value in exponential notation,
2133 // but we cannot do this if doing so will lose precision. Check here to
2134 // make sure that we only output it in exponential format if we can parse
2135 // the value back and get the same value.
2136 bool isInf = apValue.isInfinity();
2137 bool isNaN = apValue.isNaN();
2138 if (!isInf && !isNaN) {
2139 SmallString<128> strValue;
2140 apValue.toString(strValue, /*FormatPrecision=*/6, /*FormatMaxPadding=*/0,
2141 /*TruncateZero=*/false);
2143 // Check to make sure that the stringized number is not some string like
2144 // "Inf" or NaN, that atof will accept, but the lexer will not. Check
2145 // that the string matches the "[-+]?[0-9]" regex.
2146 assert(((strValue[0] >= '0
' && strValue[0] <= '9') ||
2147 ((strValue[0] ==
'-' || strValue[0] ==
'+') &&
2148 (strValue[1] >=
'0' && strValue[1] <=
'9'))) &&
2149 "[-+]?[0-9] regex does not match!");
2153 if (APFloat(apValue.getSemantics(), strValue).bitwiseIsEqual(apValue)) {
2161 apValue.toString(strValue);
2164 if (strValue.str().contains(
'.')) {
2175 APInt apInt = apValue.bitcastToAPInt();
2176 apInt.toString(str, 16,
false,
2183 return printLocationInternal(loc,
true,
true);
2187 printLocationInternal(loc,
false,
true);
2196 if (symName.empty() || !isalpha(symName.front()))
2201 symName = symName.drop_while(
2202 [](
char c) {
return llvm::isAlnum(c) || c ==
'.' || c ==
'_'; });
2203 if (symName.empty())
2208 return symName.front() ==
'<' && symName.back() ==
'>';
2213 StringRef dialectName, StringRef symString) {
2214 os << symPrefix << dialectName;
2219 os <<
'.' << symString;
2223 os << '<' << symString << '>
';
2227 static bool isBareIdentifier(StringRef name) {
2228 // By making this unsigned, the value passed in to isalnum will always be
2229 // in the range 0-255. This is important when building with MSVC because
2230 // its implementation will assert. This situation can arise when dealing
2231 // with UTF-8 multibyte characters.
2232 if (name.empty() || (!isalpha(name[0]) && name[0] != '_
'))
2234 return llvm::all_of(name.drop_front(), [](unsigned char c) {
2235 return isalnum(c) || c == '_
' || c == '$
' || c == '.
';
2241 static void printKeywordOrString(StringRef keyword, raw_ostream &os) {
2242 // If it can be represented as a bare identifier, write it directly.
2243 if (isBareIdentifier(keyword)) {
2248 // Otherwise, output the keyword wrapped in quotes with proper escaping.
2250 printEscapedString(keyword, os);
2257 static void printSymbolReference(StringRef symbolRef, raw_ostream &os) {
2258 if (symbolRef.empty()) {
2259 os << "@<<INVALID EMPTY SYMBOL>>
";
2263 printKeywordOrString(symbolRef, os);
2266 // Print out a valid ElementsAttr that is succinct and can represent any
2267 // potential shape/type, for use when eliding a large ElementsAttr.
2269 // We choose to use a dense resource ElementsAttr literal with conspicuous
2270 // content to hopefully alert readers to the fact that this has been elided.
2271 static void printElidedElementsAttr(raw_ostream &os) {
2272 os << R"(dense_resource<__elided__>)
";
2275 void AsmPrinter::Impl::printResourceHandle(
2276 const AsmDialectResourceHandle &resource) {
2277 auto *interface = cast<OpAsmDialectInterface>(resource.getDialect());
2278 ::printKeywordOrString(interface->getResourceKey(resource), os);
2279 state.getDialectResources()[resource.getDialect()].insert(resource);
2282 LogicalResult AsmPrinter::Impl::printAlias(Attribute attr) {
2283 return state.getAliasState().getAlias(attr, os);
2286 LogicalResult AsmPrinter::Impl::printAlias(Type type) {
2287 return state.getAliasState().getAlias(type, os);
2290 void AsmPrinter::Impl::printAttribute(Attribute attr,
2291 AttrTypeElision typeElision) {
2293 os << "<<NULL ATTRIBUTE>>
";
2297 // Try to print an alias for this attribute.
2298 if (succeeded(printAlias(attr)))
2300 return printAttributeImpl(attr, typeElision);
2303 void AsmPrinter::Impl::printAttributeImpl(Attribute attr,
2304 AttrTypeElision typeElision) {
2305 if (!isa<BuiltinDialect>(attr.getDialect())) {
2306 printDialectAttribute(attr);
2307 } else if (auto opaqueAttr = llvm::dyn_cast<OpaqueAttr>(attr)) {
2308 printDialectSymbol(os, "#
", opaqueAttr.getDialectNamespace(),
2309 opaqueAttr.getAttrData());
2310 } else if (llvm::isa<UnitAttr>(attr)) {
2313 } else if (auto distinctAttr = llvm::dyn_cast<DistinctAttr>(attr)) {
2314 os << "distinct[
" << state.getDistinctState().getId(distinctAttr) << "]<
";
2315 if (!llvm::isa<UnitAttr>(distinctAttr.getReferencedAttr())) {
2316 printAttribute(distinctAttr.getReferencedAttr());
2320 } else if (auto dictAttr = llvm::dyn_cast<DictionaryAttr>(attr)) {
2322 interleaveComma(dictAttr.getValue(),
2323 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2326 } else if (auto intAttr = llvm::dyn_cast<IntegerAttr>(attr)) {
2327 Type intType = intAttr.getType();
2328 if (intType.isSignlessInteger(1)) {
2329 os << (intAttr.getValue().getBoolValue() ? "true" : "false");
2331 // Boolean integer attributes always elides the type.
2335 // Only print attributes as unsigned if they are explicitly unsigned or are
2336 // signless 1-bit values. Indexes, signed values, and multi-bit signless
2337 // values print as signed.
2339 intType.isUnsignedInteger() || intType.isSignlessInteger(1);
2340 intAttr.getValue().print(os, !isUnsigned);
2342 // IntegerAttr elides the type if I64.
2343 if (typeElision == AttrTypeElision::May && intType.isSignlessInteger(64))
2346 } else if (auto floatAttr = llvm::dyn_cast<FloatAttr>(attr)) {
2347 bool printedHex = false;
2348 printFloatValue(floatAttr.getValue(), os, &printedHex);
2350 // FloatAttr elides the type if F64.
2351 if (typeElision == AttrTypeElision::May && floatAttr.getType().isF64() &&
2355 } else if (auto strAttr = llvm::dyn_cast<StringAttr>(attr)) {
2356 printEscapedString(strAttr.getValue());
2358 } else if (auto arrayAttr = llvm::dyn_cast<ArrayAttr>(attr)) {
2360 interleaveComma(arrayAttr.getValue(), [&](Attribute attr) {
2361 printAttribute(attr, AttrTypeElision::May);
2365 } else if (auto affineMapAttr = llvm::dyn_cast<AffineMapAttr>(attr)) {
2366 os << "affine_map<
";
2367 affineMapAttr.getValue().print(os);
2370 // AffineMap always elides the type.
2373 } else if (auto integerSetAttr = llvm::dyn_cast<IntegerSetAttr>(attr)) {
2374 os << "affine_set<
";
2375 integerSetAttr.getValue().print(os);
2378 // IntegerSet always elides the type.
2381 } else if (auto typeAttr = llvm::dyn_cast<TypeAttr>(attr)) {
2382 printType(typeAttr.getValue());
2384 } else if (auto refAttr = llvm::dyn_cast<SymbolRefAttr>(attr)) {
2385 printSymbolReference(refAttr.getRootReference().getValue(), os);
2386 for (FlatSymbolRefAttr nestedRef : refAttr.getNestedReferences()) {
2388 printSymbolReference(nestedRef.getValue(), os);
2391 } else if (auto intOrFpEltAttr =
2392 llvm::dyn_cast<DenseIntOrFPElementsAttr>(attr)) {
2393 if (printerFlags.shouldElideElementsAttr(intOrFpEltAttr)) {
2394 printElidedElementsAttr(os);
2397 printDenseIntOrFPElementsAttr(intOrFpEltAttr, /*allowHex=*/true);
2401 } else if (auto strEltAttr = llvm::dyn_cast<DenseStringElementsAttr>(attr)) {
2402 if (printerFlags.shouldElideElementsAttr(strEltAttr)) {
2403 printElidedElementsAttr(os);
2406 printDenseStringElementsAttr(strEltAttr);
2410 } else if (auto sparseEltAttr = llvm::dyn_cast<SparseElementsAttr>(attr)) {
2411 if (printerFlags.shouldElideElementsAttr(sparseEltAttr.getIndices()) ||
2412 printerFlags.shouldElideElementsAttr(sparseEltAttr.getValues())) {
2413 printElidedElementsAttr(os);
2416 DenseIntElementsAttr indices = sparseEltAttr.getIndices();
2417 if (indices.getNumElements() != 0) {
2418 printDenseIntOrFPElementsAttr(indices, /*allowHex=*/false);
2420 printDenseElementsAttr(sparseEltAttr.getValues(), /*allowHex=*/true);
2424 } else if (auto stridedLayoutAttr = llvm::dyn_cast<StridedLayoutAttr>(attr)) {
2425 stridedLayoutAttr.print(os);
2426 } else if (auto denseArrayAttr = llvm::dyn_cast<DenseArrayAttr>(attr)) {
2428 printType(denseArrayAttr.getElementType());
2429 if (!denseArrayAttr.empty()) {
2431 printDenseArrayAttr(denseArrayAttr);
2435 } else if (auto resourceAttr =
2436 llvm::dyn_cast<DenseResourceElementsAttr>(attr)) {
2437 os << "dense_resource<
";
2438 printResourceHandle(resourceAttr.getRawHandle());
2440 } else if (auto locAttr = llvm::dyn_cast<LocationAttr>(attr)) {
2441 printLocation(locAttr);
2443 llvm::report_fatal_error("Unknown builtin attribute
");
2445 // Don't print the type if we must elide it, or if it is a None type.
2446 if (typeElision != AttrTypeElision::Must) {
2447 if (auto typedAttr = llvm::dyn_cast<TypedAttr>(attr)) {
2448 Type attrType = typedAttr.getType();
2449 if (!llvm::isa<NoneType>(attrType)) {
2451 printType(attrType);
2458 static void printDenseIntElement(const APInt &value, raw_ostream &os,
2460 if (type.isInteger(1))
2461 os << (value.getBoolValue() ? "
true" : "false");
2463 value.print(os, !type.isUnsignedInteger());
2467 printDenseElementsAttrImpl(bool isSplat, ShapedType type, raw_ostream &os,
2468 function_ref<void(unsigned)> printEltFn) {
2469 // Special case for 0-d and splat tensors.
2471 return printEltFn(0);
2473 // Special case for degenerate tensors.
2474 auto numElements = type.getNumElements();
2475 if (numElements == 0)
2478 // We use a mixed-radix counter to iterate through the shape. When we bump a
2479 // non-least-significant digit, we emit a close bracket. When we next emit an
2480 // element we re-open all closed brackets.
2482 // The mixed-radix counter, with radices in 'shape'.
2483 int64_t rank = type.getRank();
2484 SmallVector<unsigned, 4> counter(rank, 0);
2485 // The number of brackets that have been opened and not closed.
2486 unsigned openBrackets = 0;
2488 auto shape = type.getShape();
2489 auto bumpCounter = [&] {
2490 // Bump the least significant digit.
2491 ++counter[rank - 1];
2492 // Iterate backwards bubbling back the increment.
2493 for (unsigned i = rank - 1; i > 0; --i)
2494 if (counter[i] >= shape[i]) {
2495 // Index 'i' is rolled over. Bump (i-1) and close a bracket.
2503 for (unsigned idx = 0, e = numElements; idx != e; ++idx) {
2506 while (openBrackets++ < rank)
2508 openBrackets = rank;
2512 while (openBrackets-- > 0)
2516 void AsmPrinter::Impl::printDenseElementsAttr(DenseElementsAttr attr,
2518 if (auto stringAttr = llvm::dyn_cast<DenseStringElementsAttr>(attr))
2519 return printDenseStringElementsAttr(stringAttr);
2521 printDenseIntOrFPElementsAttr(llvm::cast<DenseIntOrFPElementsAttr>(attr),
2525 void AsmPrinter::Impl::printDenseIntOrFPElementsAttr(
2526 DenseIntOrFPElementsAttr attr, bool allowHex) {
2527 auto type = attr.getType();
2528 auto elementType = type.getElementType();
2530 // Check to see if we should format this attribute as a hex string.
2531 if (allowHex && printerFlags.shouldPrintElementsAttrWithHex(attr)) {
2532 ArrayRef<char> rawData = attr.getRawData();
2533 if (llvm::endianness::native == llvm::endianness::big) {
2534 // Convert endianess in big-endian(BE) machines. `rawData` is BE in BE
2535 // machines. It is converted here to print in LE format.
2536 SmallVector<char, 64> outDataVec(rawData.size());
2537 MutableArrayRef<char> convRawData(outDataVec);
2538 DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
2539 rawData, convRawData, type);
2540 printHexString(convRawData);
2542 printHexString(rawData);
2548 if (ComplexType complexTy = llvm::dyn_cast<ComplexType>(elementType)) {
2549 Type complexElementType = complexTy.getElementType();
2550 // Note: The if and else below had a common lambda function which invoked
2551 // printDenseElementsAttrImpl. This lambda was hitting a bug in gcc 9.1,9.2
2552 // and hence was replaced.
2553 if (llvm::isa<IntegerType>(complexElementType)) {
2554 auto valueIt = attr.value_begin<std::complex<APInt>>();
2555 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2556 auto complexValue = *(valueIt + index);
2558 printDenseIntElement(complexValue.real(), os, complexElementType);
2560 printDenseIntElement(complexValue.imag(), os, complexElementType);
2564 auto valueIt = attr.value_begin<std::complex<APFloat>>();
2565 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2566 auto complexValue = *(valueIt + index);
2568 printFloatValue(complexValue.real(), os);
2570 printFloatValue(complexValue.imag(), os);
2574 } else if (elementType.isIntOrIndex()) {
2575 auto valueIt = attr.value_begin<APInt>();
2576 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2577 printDenseIntElement(*(valueIt + index), os, elementType);
2580 assert(llvm::isa<FloatType>(elementType) && "unexpected element type
");
2581 auto valueIt = attr.value_begin<APFloat>();
2582 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2583 printFloatValue(*(valueIt + index), os);
2588 void AsmPrinter::Impl::printDenseStringElementsAttr(
2589 DenseStringElementsAttr attr) {
2590 ArrayRef<StringRef> data = attr.getRawStringData();
2591 auto printFn = [&](unsigned index) { printEscapedString(data[index]); };
2592 printDenseElementsAttrImpl(attr.isSplat(), attr.getType(), os, printFn);
2595 void AsmPrinter::Impl::printDenseArrayAttr(DenseArrayAttr attr) {
2596 Type type = attr.getElementType();
2597 unsigned bitwidth = type.isInteger(1) ? 8 : type.getIntOrFloatBitWidth();
2598 unsigned byteSize = bitwidth / 8;
2599 ArrayRef<char> data = attr.getRawData();
2601 auto printElementAt = [&](unsigned i) {
2602 APInt value(bitwidth, 0);
2604 llvm::LoadIntFromMemory(
2605 value, reinterpret_cast<const uint8_t *>(data.begin() + byteSize * i),
2608 // Print the data as-is or as a float.
2609 if (type.isIntOrIndex()) {
2610 printDenseIntElement(value, getStream(), type);
2612 APFloat fltVal(llvm::cast<FloatType>(type).getFloatSemantics(), value);
2613 printFloatValue(fltVal, getStream());
2616 llvm::interleaveComma(llvm::seq<unsigned>(0, attr.size()), getStream(),
2620 void AsmPrinter::Impl::printType(Type type) {
2622 os << "<<NULL TYPE>>
";
2626 // Try to print an alias for this type.
2627 if (succeeded(printAlias(type)))
2629 return printTypeImpl(type);
2632 void AsmPrinter::Impl::printTypeImpl(Type type) {
2633 TypeSwitch<Type>(type)
2634 .Case<OpaqueType>([&](OpaqueType opaqueTy) {
2635 printDialectSymbol(os, "!
", opaqueTy.getDialectNamespace(),
2636 opaqueTy.getTypeData());
2638 .Case<IndexType>([&](Type) { os << "index
"; })
2639 .Case<Float4E2M1FNType>([&](Type) { os << "f4E2M1FN
"; })
2640 .Case<Float6E2M3FNType>([&](Type) { os << "f6E2M3FN
"; })
2641 .Case<Float6E3M2FNType>([&](Type) { os << "f6E3M2FN
"; })
2642 .Case<Float8E5M2Type>([&](Type) { os << "f8E5M2
"; })
2643 .Case<Float8E4M3Type>([&](Type) { os << "f8E4M3
"; })
2644 .Case<Float8E4M3FNType>([&](Type) { os << "f8E4M3FN
"; })
2645 .Case<Float8E5M2FNUZType>([&](Type) { os << "f8E5M2FNUZ
"; })
2646 .Case<Float8E4M3FNUZType>([&](Type) { os << "f8E4M3FNUZ
"; })
2647 .Case<Float8E4M3B11FNUZType>([&](Type) { os << "f8E4M3B11FNUZ
"; })
2648 .Case<Float8E3M4Type>([&](Type) { os << "f8E3M4
"; })
2649 .Case<Float8E8M0FNUType>([&](Type) { os << "f8E8M0FNU
"; })
2650 .Case<BFloat16Type>([&](Type) { os << "bf16"; })
2651 .Case<Float16Type>([&](Type) { os << "f16"; })
2652 .Case<FloatTF32Type>([&](Type) { os << "tf32
"; })
2653 .Case<Float32Type>([&](Type) { os << "f32
"; })
2654 .Case<Float64Type>([&](Type) { os << "f64
"; })
2655 .Case<Float80Type>([&](Type) { os << "f80
"; })
2656 .Case<Float128Type>([&](Type) { os << "f128
"; })
2657 .Case<IntegerType>([&](IntegerType integerTy) {
2658 if (integerTy.isSigned())
2660 else if (integerTy.isUnsigned())
2662 os << 'i' << integerTy.getWidth();
2664 .Case<FunctionType>([&](FunctionType funcTy) {
2666 interleaveComma(funcTy.getInputs(), [&](Type ty) { printType(ty); });
2668 ArrayRef<Type> results = funcTy.getResults();
2669 if (results.size() == 1 && !llvm::isa<FunctionType>(results[0])) {
2670 printType(results[0]);
2673 interleaveComma(results, [&](Type ty) { printType(ty); });
2677 .Case<VectorType>([&](VectorType vectorTy) {
2678 auto scalableDims = vectorTy.getScalableDims();
2680 auto vShape = vectorTy.getShape();
2681 unsigned lastDim = vShape.size();
2682 unsigned dimIdx = 0;
2683 for (dimIdx = 0; dimIdx < lastDim; dimIdx++) {
2684 if (!scalableDims.empty() && scalableDims[dimIdx])
2686 os << vShape[dimIdx];
2687 if (!scalableDims.empty() && scalableDims[dimIdx])
2691 printType(vectorTy.getElementType());
2694 .Case<RankedTensorType>([&](RankedTensorType tensorTy) {
2696 printDimensionList(tensorTy.getShape());
2697 if (!tensorTy.getShape().empty())
2699 printType(tensorTy.getElementType());
2700 // Only print the encoding attribute value if set.
2701 if (tensorTy.getEncoding()) {
2703 printAttribute(tensorTy.getEncoding());
2707 .Case<UnrankedTensorType>([&](UnrankedTensorType tensorTy) {
2709 printType(tensorTy.getElementType());
2712 .Case<MemRefType>([&](MemRefType memrefTy) {
2714 printDimensionList(memrefTy.getShape());
2715 if (!memrefTy.getShape().empty())
2717 printType(memrefTy.getElementType());
2718 MemRefLayoutAttrInterface layout = memrefTy.getLayout();
2719 if (!llvm::isa<AffineMapAttr>(layout) || !layout.isIdentity()) {
2721 printAttribute(memrefTy.getLayout(), AttrTypeElision::May);
2723 // Only print the memory space if it is the non-default one.
2724 if (memrefTy.getMemorySpace()) {
2726 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2730 .Case<UnrankedMemRefType>([&](UnrankedMemRefType memrefTy) {
2732 printType(memrefTy.getElementType());
2733 // Only print the memory space if it is the non-default one.
2734 if (memrefTy.getMemorySpace()) {
2736 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2740 .Case<ComplexType>([&](ComplexType complexTy) {
2742 printType(complexTy.getElementType());
2745 .Case<TupleType>([&](TupleType tupleTy) {
2747 interleaveComma(tupleTy.getTypes(),
2748 [&](Type type) { printType(type); });
2751 .Case<NoneType>([&](Type) { os << "none
"; })
2752 .Default([&](Type type) { return printDialectType(type); });
2755 void AsmPrinter::Impl::printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
2756 ArrayRef<StringRef> elidedAttrs,
2758 // If there are no attributes, then there is nothing to be done.
2762 // Functor used to print a filtered attribute list.
2763 auto printFilteredAttributesFn = [&](auto filteredAttrs) {
2764 // Print the 'attributes' keyword if necessary.
2766 os << " attributes
";
2768 // Otherwise, print them all out in braces.
2770 interleaveComma(filteredAttrs,
2771 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2775 // If no attributes are elided, we can directly print with no filtering.
2776 if (elidedAttrs.empty())
2777 return printFilteredAttributesFn(attrs);
2779 // Otherwise, filter out any attributes that shouldn't be included.
2780 llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
2782 auto filteredAttrs = llvm::make_filter_range(attrs, [&](NamedAttribute attr) {
2783 return !elidedAttrsSet.contains(attr.getName().strref());
2785 if (!filteredAttrs.empty())
2786 printFilteredAttributesFn(filteredAttrs);
2788 void AsmPrinter::Impl::printNamedAttribute(NamedAttribute attr) {
2789 // Print the name without quotes if possible.
2790 ::printKeywordOrString(attr.getName().strref(), os);
2792 // Pretty printing elides the attribute value for unit attributes.
2793 if (llvm::isa<UnitAttr>(attr.getValue()))
2797 printAttribute(attr.getValue());
2800 void AsmPrinter::Impl::printDialectAttribute(Attribute attr) {
2801 auto &dialect = attr.getDialect();
2803 // Ask the dialect to serialize the attribute to a string.
2804 std::string attrName;
2806 llvm::raw_string_ostream attrNameStr(attrName);
2807 Impl subPrinter(attrNameStr, state);
2808 DialectAsmPrinter printer(subPrinter);
2809 dialect.printAttribute(attr, printer);
2811 printDialectSymbol(os, "#
", dialect.getNamespace(), attrName);
2814 void AsmPrinter::Impl::printDialectType(Type type) {
2815 auto &dialect = type.getDialect();
2817 // Ask the dialect to serialize the type to a string.
2818 std::string typeName;
2820 llvm::raw_string_ostream typeNameStr(typeName);
2821 Impl subPrinter(typeNameStr, state);
2822 DialectAsmPrinter printer(subPrinter);
2823 dialect.printType(type, printer);
2825 printDialectSymbol(os, "!
", dialect.getNamespace(), typeName);
2828 void AsmPrinter::Impl::printEscapedString(StringRef str) {
2830 llvm::printEscapedString(str, os);
2835 os <<
"\"0x" << llvm::toHex(str) <<
"\"";
2838 printHexString(StringRef(data.data(), data.size()));
2842 return state.pushCyclicPrinting(opaquePointer);
2858 assert(
impl &&
"expected AsmPrinter::getStream to be overriden");
2859 return impl->getStream();
2864 assert(
impl &&
"expected AsmPrinter::printFloat to be overriden");
2869 assert(
impl &&
"expected AsmPrinter::printType to be overriden");
2870 impl->printType(type);
2874 assert(
impl &&
"expected AsmPrinter::printAttribute to be overriden");
2875 impl->printAttribute(attr);
2879 assert(
impl &&
"expected AsmPrinter::printAlias to be overriden");
2880 return impl->printAlias(attr);
2884 assert(
impl &&
"expected AsmPrinter::printAlias to be overriden");
2885 return impl->printAlias(type);
2890 "expected AsmPrinter::printAttributeWithoutType to be overriden");
2895 assert(
impl &&
"expected AsmPrinter::printKeywordOrString to be overriden");
2900 assert(
impl &&
"expected AsmPrinter::printString to be overriden");
2902 printEscapedString(keyword,
getStream());
2907 assert(
impl &&
"expected AsmPrinter::printSymbolName to be overriden");
2912 assert(
impl &&
"expected AsmPrinter::printResourceHandle to be overriden");
2913 impl->printResourceHandle(resource);
2921 return impl->pushCyclicPrinting(opaquePointer);
2932 printAffineExprInternal(expr, BindingStrength::Weak, printValueName);
2938 const char *binopSpelling =
nullptr;
2941 unsigned pos = cast<AffineSymbolExpr>(expr).getPosition();
2943 printValueName(pos,
true);
2949 unsigned pos = cast<AffineDimExpr>(expr).getPosition();
2951 printValueName(pos,
false);
2957 os << cast<AffineConstantExpr>(expr).getValue();
2960 binopSpelling =
" + ";
2963 binopSpelling =
" * ";
2966 binopSpelling =
" floordiv ";
2969 binopSpelling =
" ceildiv ";
2972 binopSpelling =
" mod ";
2976 auto binOp = cast<AffineBinaryOpExpr>(expr);
2982 if (enclosingTightness == BindingStrength::Strong)
2986 auto rhsConst = dyn_cast<AffineConstantExpr>(rhsExpr);
2988 rhsConst.getValue() == -1) {
2990 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
2991 if (enclosingTightness == BindingStrength::Strong)
2996 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
2998 os << binopSpelling;
2999 printAffineExprInternal(rhsExpr, BindingStrength::Strong, printValueName);
3001 if (enclosingTightness == BindingStrength::Strong)
3007 if (enclosingTightness == BindingStrength::Strong)
3012 if (
auto rhs = dyn_cast<AffineBinaryOpExpr>(rhsExpr)) {
3015 if (
auto rrhs = dyn_cast<AffineConstantExpr>(rrhsExpr)) {
3016 if (rrhs.getValue() == -1) {
3017 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
3021 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
3024 printAffineExprInternal(rhs.getLHS(), BindingStrength::Weak,
3028 if (enclosingTightness == BindingStrength::Strong)
3033 if (rrhs.getValue() < -1) {
3034 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
3037 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
3039 os <<
" * " << -rrhs.getValue();
3040 if (enclosingTightness == BindingStrength::Strong)
3049 if (
auto rhsConst = dyn_cast<AffineConstantExpr>(rhsExpr)) {
3050 if (rhsConst.getValue() < 0) {
3051 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
3052 os <<
" - " << -rhsConst.getValue();
3053 if (enclosingTightness == BindingStrength::Strong)
3059 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
3062 printAffineExprInternal(rhsExpr, BindingStrength::Weak, printValueName);
3064 if (enclosingTightness == BindingStrength::Strong)
3069 printAffineExprInternal(expr, BindingStrength::Weak);
3070 isEq ? os <<
" == 0" : os <<
" >= 0";
3076 for (
int i = 0; i < (int)map.
getNumDims() - 1; ++i)
3077 os <<
'd' << i <<
", ";
3086 os <<
's' << i <<
", ";
3095 [&](
AffineExpr expr) { printAffineExpr(expr); });
3102 for (
unsigned i = 1; i < set.
getNumDims(); ++i)
3103 os <<
'd' << i - 1 <<
", ";
3112 os <<
's' << i <<
", ";
3121 for (
int i = 1; i < numConstraints; ++i) {
3125 if (numConstraints >= 1)
3126 printAffineConstraint(set.
getConstraint(numConstraints - 1),
3127 set.
isEq(numConstraints - 1));
3142 explicit OperationPrinter(raw_ostream &os,
AsmStateImpl &state)
3146 void printTopLevelOperation(
Operation *op);
3150 void printFullOpWithIndentAndLoc(
Operation *op);
3156 void printCustomOrGenericOp(
Operation *op)
override;
3158 void printGenericOp(
Operation *op,
bool printOpName)
override;
3161 void printBlockName(
Block *block);
3166 void print(
Block *block,
bool printBlockArgs =
true,
3167 bool printBlockTerminator =
true);
3170 void printValueID(
Value value,
bool printResultNo =
true,
3171 raw_ostream *streamOverride =
nullptr)
const;
3175 raw_ostream *streamOverride =
nullptr)
const;
3183 void printOptionalLocationSpecifier(
Location loc)
override {
3184 printTrailingLocation(loc);
3191 os.indent(currentIndent);
3195 void increaseIndent()
override { currentIndent += indentWidth; }
3198 void decreaseIndent()
override { currentIndent -= indentWidth; }
3207 bool omitType =
false)
override;
3210 void printOperand(
Value value)
override { printValueID(value); }
3211 void printOperand(
Value value, raw_ostream &os)
override {
3212 printValueID(value,
true, &os);
3220 void printOptionalAttrDictWithKeyword(
3228 void printSuccessor(
Block *successor)
override;
3232 void printSuccessorAndUseList(
Block *successor,
3237 bool printBlockTerminators,
bool printEmptyBlock)
override;
3244 state.getSSANameState().shadowRegionArgs(region, namesToUse);
3249 void printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3264 void printValueUsers(
Value value);
3268 void printUserIDs(
Operation *user,
bool prefixComma =
false);
3276 using PrintFn =
function_ref<void(StringRef, ValueFn)>;
3278 ResourceBuilder(PrintFn printFn) : printFn(printFn) {}
3279 ~ResourceBuilder()
override =
default;
3281 void buildBool(StringRef key,
bool data)
final {
3282 printFn(key, [&](raw_ostream &os) { os << (data ?
"true" :
"false"); });
3285 void buildString(StringRef key, StringRef data)
final {
3286 printFn(key, [&](raw_ostream &os) {
3288 llvm::printEscapedString(data, os);
3294 uint32_t dataAlignment)
final {
3295 printFn(key, [&](raw_ostream &os) {
3297 llvm::support::ulittle32_t dataAlignmentLE(dataAlignment);
3299 << llvm::toHex(StringRef(
reinterpret_cast<char *
>(&dataAlignmentLE),
3300 sizeof(dataAlignment)))
3301 << llvm::toHex(StringRef(data.data(), data.size())) <<
"\"";
3310 void printFileMetadataDictionary(
Operation *op);
3316 void printResourceFileMetadata(
function_ref<
void()> checkAddMetadataDict,
3327 const static unsigned indentWidth = 2;
3330 unsigned currentIndent = 0;
3334 void OperationPrinter::printTopLevelOperation(
Operation *op) {
3336 state.getAliasState().printNonDeferredAliases(*
this, newLine);
3339 printFullOpWithIndentAndLoc(op);
3343 state.getAliasState().printDeferredAliases(*
this, newLine);
3346 printFileMetadataDictionary(op);
3349 void OperationPrinter::printFileMetadataDictionary(
Operation *op) {
3350 bool sawMetadataEntry =
false;
3351 auto checkAddMetadataDict = [&] {
3352 if (!std::exchange(sawMetadataEntry,
true))
3353 os << newLine <<
"{-#" << newLine;
3357 printResourceFileMetadata(checkAddMetadataDict, op);
3360 if (sawMetadataEntry)
3361 os << newLine <<
"#-}" << newLine;
3364 void OperationPrinter::printResourceFileMetadata(
3367 bool hadResource =
false;
3368 bool needResourceComma =
false;
3369 bool needEntryComma =
false;
3370 auto processProvider = [&](StringRef dictName, StringRef name,
auto &provider,
3371 auto &&...providerArgs) {
3372 bool hadEntry =
false;
3373 auto printFn = [&](StringRef key, ResourceBuilder::ValueFn valueFn) {
3374 checkAddMetadataDict();
3376 std::string resourceStr;
3377 auto printResourceStr = [&](raw_ostream &os) { os << resourceStr; };
3378 std::optional<uint64_t> charLimit =
3380 if (charLimit.has_value()) {
3381 llvm::raw_string_ostream ss(resourceStr);
3385 if (resourceStr.size() > charLimit.value())
3389 valueFn = printResourceStr;
3393 if (!std::exchange(hadResource,
true)) {
3394 if (needResourceComma)
3395 os <<
"," << newLine;
3396 os <<
" " << dictName <<
"_resources: {" << newLine;
3399 if (!std::exchange(hadEntry,
true)) {
3401 os <<
"," << newLine;
3402 os <<
" " << name <<
": {" << newLine;
3404 os <<
"," << newLine;
3412 ResourceBuilder entryBuilder(printFn);
3413 provider.buildResources(op, providerArgs..., entryBuilder);
3415 needEntryComma |= hadEntry;
3417 os << newLine <<
" }";
3423 auto &dialectResources = state.getDialectResources();
3424 StringRef name = interface.getDialect()->getNamespace();
3425 auto it = dialectResources.find(interface.getDialect());
3426 if (it != dialectResources.end())
3427 processProvider(
"dialect", name, interface, it->second);
3429 processProvider(
"dialect", name, interface,
3433 os << newLine <<
" }";
3437 needEntryComma =
false;
3438 needResourceComma = hadResource;
3439 hadResource =
false;
3440 for (
const auto &printer : state.getResourcePrinters())
3441 processProvider(
"external", printer.getName(), printer);
3443 os << newLine <<
" }";
3451 void OperationPrinter::printRegionArgument(
BlockArgument arg,
3459 printOptionalAttrDict(argAttrs);
3461 printTrailingLocation(arg.
getLoc(),
false);
3464 void OperationPrinter::printFullOpWithIndentAndLoc(
Operation *op) {
3466 state.registerOperationLocation(op, newLine.curLine, currentIndent);
3468 os.indent(currentIndent);
3470 printTrailingLocation(op->
getLoc());
3472 printUsersComment(op);
3475 void OperationPrinter::printFullOp(
Operation *op) {
3477 auto printResultGroup = [&](
size_t resultNo,
size_t resultCount) {
3478 printValueID(op->
getResult(resultNo),
false);
3479 if (resultCount > 1)
3480 os <<
':' << resultCount;
3484 ArrayRef<int> resultGroups = state.getSSANameState().getOpResultGroups(op);
3485 if (!resultGroups.empty()) {
3488 interleaveComma(llvm::seq<int>(0, resultGroups.size() - 1), [&](
int i) {
3489 printResultGroup(resultGroups[i],
3490 resultGroups[i + 1] - resultGroups[i]);
3493 printResultGroup(resultGroups.back(), numResults - resultGroups.back());
3496 printResultGroup(0, numResults);
3502 printCustomOrGenericOp(op);
3505 void OperationPrinter::printUsersComment(
Operation *op) {
3509 printOperationID(op);
3510 }
else if (numResults && op->
use_empty()) {
3512 }
else if (numResults && !op->
use_empty()) {
3515 unsigned usedInNResults = 0;
3516 unsigned usedInNOperations = 0;
3519 if (userSet.insert(user).second) {
3520 ++usedInNOperations;
3521 usedInNResults += user->getNumResults();
3526 bool exactlyOneUniqueUse =
3527 usedInNResults <= 1 && usedInNOperations <= 1 && numResults == 1;
3528 os <<
" // " << (exactlyOneUniqueUse ?
"user" :
"users") <<
": ";
3529 bool shouldPrintBrackets = numResults > 1;
3530 auto printOpResult = [&](
OpResult opResult) {
3531 if (shouldPrintBrackets)
3533 printValueUsers(opResult);
3534 if (shouldPrintBrackets)
3538 interleaveComma(op->
getResults(), printOpResult);
3542 void OperationPrinter::printUsersComment(
BlockArgument arg) {
3548 os <<
" is used by ";
3549 printValueUsers(arg);
3554 void OperationPrinter::printValueUsers(
Value value) {
3562 if (userSet.insert(user).second)
3563 printUserIDs(user, index);
3567 void OperationPrinter::printUserIDs(
Operation *user,
bool prefixComma) {
3572 printOperationID(user);
3575 [
this](
Value result) { printValueID(result); });
3579 void OperationPrinter::printCustomOrGenericOp(
Operation *op) {
3585 opInfo->printAssembly(op, *
this, defaultDialectStack.back());
3590 if (
auto opPrinter = dialect->getOperationPrinter(op)) {
3595 if (name.count(
'.') == 1)
3596 name.consume_front((defaultDialectStack.back() +
".").str());
3600 opPrinter(op, *
this);
3607 printGenericOp(op,
true);
3610 void OperationPrinter::printGenericOp(
Operation *op,
bool printOpName) {
3614 interleaveComma(op->
getOperands(), [&](
Value value) { printValueID(value); });
3621 [&](
Block *successor) { printBlockName(successor); });
3633 if (op->getNumRegions() != 0) {
3635 interleaveComma(op->getRegions(), [&](Region ®ion) {
3636 printRegion(region, /*printEntryBlockArgs=*/true,
3637 /*printBlockTerminators=*/true, /*printEmptyBlock=*/true);
3642 printOptionalAttrDict(op->getPropertiesStorage()
3643 ? llvm::to_vector(op->getDiscardableAttrs())
3646 // Print the type signature of the operation.
3648 printFunctionalType(op);
3651 void OperationPrinter::printBlockName(Block *block) {
3652 os << state.getSSANameState().getBlockInfo(block).name;
3655 void OperationPrinter::print(Block *block, bool printBlockArgs,
3656 bool printBlockTerminator) {
3657 // Print the block label and argument list if requested.
3658 if (printBlockArgs) {
3659 os.indent(currentIndent);
3660 printBlockName(block);
3662 // Print the argument list if non-empty.
3663 if (!block->args_empty()) {
3665 interleaveComma(block->getArguments(), [&](BlockArgument arg) {
3668 printType(arg.getType());
3669 // TODO: We should allow location aliases on block arguments.
3670 printTrailingLocation(arg.getLoc(), /*allowAlias*/ false);
3676 // Print out some context information about the predecessors of this block.
3677 if (!block->getParent()) {
3678 os << " // block is not in a region!";
3679 } else if (block->hasNoPredecessors()) {
3680 if (!block->isEntryBlock())
3681 os << " // no predecessors";
3682 } else if (auto *pred = block->getSinglePredecessor()) {
3684 printBlockName(pred);
3686 // We want to print the predecessors in a stable order, not in
3687 // whatever order the use-list is in, so gather and sort them.
3688 SmallVector<BlockInfo, 4> predIDs;
3689 for (auto *pred : block->getPredecessors())
3690 predIDs.push_back(state.getSSANameState().getBlockInfo(pred));
3691 llvm::sort(predIDs, [](BlockInfo lhs, BlockInfo rhs) {
3692 return lhs.ordering < rhs.ordering;
3695 os << " // " << predIDs.size() << " preds: ";
3697 interleaveComma(predIDs, [&](BlockInfo pred) { os << pred.name; });
3702 currentIndent += indentWidth;
3704 if (printerFlags.shouldPrintValueUsers()) {
3705 for (BlockArgument arg : block->getArguments()) {
3706 os.indent(currentIndent);
3707 printUsersComment(arg);
3711 bool hasTerminator =
3712 !block->empty() && block->back().hasTrait<OpTrait::IsTerminator>();
3713 auto range = llvm::make_range(
3715 std::prev(block->end(),
3716 (!hasTerminator || printBlockTerminator) ? 0 : 1));
3717 for (auto &op : range) {
3718 printFullOpWithIndentAndLoc(&op);
3721 currentIndent -= indentWidth;
3724 void OperationPrinter::printValueID(Value value, bool printResultNo,
3725 raw_ostream *streamOverride) const {
3726 state.getSSANameState().printValueID(value, printResultNo,
3727 streamOverride ? *streamOverride : os);
3730 void OperationPrinter::printOperationID(Operation *op,
3731 raw_ostream *streamOverride) const {
3732 state.getSSANameState().printOperationID(op, streamOverride ? *streamOverride
3736 void OperationPrinter::printSuccessor(Block *successor) {
3737 printBlockName(successor);
3740 void OperationPrinter::printSuccessorAndUseList(Block *successor,
3741 ValueRange succOperands) {
3742 printBlockName(successor);
3743 if (succOperands.empty())
3747 interleaveComma(succOperands,
3748 [this](Value operand) { printValueID(operand); });
3750 interleaveComma(succOperands,
3751 [this](Value operand) { printType(operand.getType()); });
3755 void OperationPrinter::printRegion(Region ®ion, bool printEntryBlockArgs,
3756 bool printBlockTerminators,
3757 bool printEmptyBlock) {
3758 if (printerFlags.shouldSkipRegions()) {
3762 os << "{" << newLine;
3763 if (!region.empty()) {
3764 auto restoreDefaultDialect =
3765 llvm::make_scope_exit([&]() { defaultDialectStack.pop_back(); });
3766 if (auto iface = dyn_cast<OpAsmOpInterface>(region.getParentOp()))
3767 defaultDialectStack.push_back(iface.getDefaultDialect());
3769 defaultDialectStack.push_back("");
3771 auto *entryBlock = ®ion.front();
3772 // Force printing the block header if printEmptyBlock is set and the block
3773 // is empty or if printEntryBlockArgs is set and there are arguments to
3775 bool shouldAlwaysPrintBlockHeader =
3776 (printEmptyBlock && entryBlock->empty()) ||
3777 (printEntryBlockArgs && entryBlock->getNumArguments() != 0);
3778 print(entryBlock, shouldAlwaysPrintBlockHeader, printBlockTerminators);
3779 for (auto &b : llvm::drop_begin(region.getBlocks(), 1))
3782 os.indent(currentIndent) << "}";
3785 void OperationPrinter::printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3786 ValueRange operands) {
3788 os << "<<NULL AFFINE MAP>>";
3791 AffineMap map = mapAttr.getValue();
3792 unsigned numDims = map.getNumDims();
3793 auto printValueName = [&](unsigned pos, bool isSymbol) {
3794 unsigned index = isSymbol ? numDims + pos : pos;
3795 assert(index < operands.size());
3798 printValueID(operands[index]);
3803 interleaveComma(map.getResults(), [&](AffineExpr expr) {
3804 printAffineExpr(expr, printValueName);
3808 void OperationPrinter::printAffineExprOfSSAIds(AffineExpr expr,
3809 ValueRange dimOperands,
3810 ValueRange symOperands) {
3811 auto printValueName = [&](unsigned pos, bool isSymbol) {
3813 return printValueID(dimOperands[pos]);
3815 printValueID(symOperands[pos]);
3818 printAffineExpr(expr, printValueName);
3821 //===----------------------------------------------------------------------===//
3822 // print and dump methods
3823 //===----------------------------------------------------------------------===//
3825 void Attribute::print(raw_ostream &os, bool elideType) const {
3827 os << "<<NULL ATTRIBUTE>>";
3831 AsmState state(getContext());
3832 print(os, state, elideType);
3834 void Attribute::print(raw_ostream &os, AsmState &state, bool elideType) const {
3835 using AttrTypeElision = AsmPrinter::Impl::AttrTypeElision;
3836 AsmPrinter::Impl(os, state.getImpl())
3837 .printAttribute(*this, elideType ? AttrTypeElision::Must
3838 : AttrTypeElision::Never);
3841 void Attribute::dump() const {
3842 print(llvm::errs());
3843 llvm::errs() << "\n";
3846 void Attribute::printStripped(raw_ostream &os, AsmState &state) const {
3848 os << "<<NULL ATTRIBUTE>>";
3852 AsmPrinter::Impl subPrinter(os, state.getImpl());
3853 if (succeeded(subPrinter.printAlias(*this)))
3856 auto &dialect = this->getDialect();
3857 uint64_t posPrior = os.tell();
3858 DialectAsmPrinter printer(subPrinter);
3859 dialect.printAttribute(*this, printer);
3860 if (posPrior != os.tell())
3863 // Fallback to printing with prefix if the above failed to write anything
3864 // to the output stream.
3867 void Attribute::printStripped(raw_ostream &os) const {
3869 os << "<<NULL ATTRIBUTE>>";
3873 AsmState state(getContext());
3874 printStripped(os, state);
3877 void Type::print(raw_ostream &os) const {
3879 os << "<<NULL TYPE>>";
3883 AsmState state(getContext());
3886 void Type::print(raw_ostream &os, AsmState &state) const {
3887 AsmPrinter::Impl(os, state.getImpl()).printType(*this);
3890 void Type::dump() const {
3891 print(llvm::errs());
3892 llvm::errs() << "\n";
3895 void AffineMap::dump() const {
3896 print(llvm::errs());
3897 llvm::errs() << "\n";
3900 void IntegerSet::dump() const {
3901 print(llvm::errs());
3902 llvm::errs() << "\n";
3905 void AffineExpr::print(raw_ostream &os) const {
3907 os << "<<NULL AFFINE EXPR>>";
3910 AsmState state(getContext());
3911 AsmPrinter::Impl(os, state.getImpl()).printAffineExpr(*this);
3914 void AffineExpr::dump() const {
3915 print(llvm::errs());
3916 llvm::errs() << "\n";
3919 void AffineMap::print(raw_ostream &os) const {
3921 os << "<<NULL AFFINE MAP>>";
3924 AsmState state(getContext());
3925 AsmPrinter::Impl(os, state.getImpl()).printAffineMap(*this);
3928 void IntegerSet::print(raw_ostream &os) const {
3929 AsmState state(getContext());
3930 AsmPrinter::Impl(os, state.getImpl()).printIntegerSet(*this);
3933 void Value::print(raw_ostream &os) const { print(os, OpPrintingFlags()); }
3934 void Value::print(raw_ostream &os, const OpPrintingFlags &flags) const {
3936 os << "<<NULL VALUE>>";
3940 if (auto *op = getDefiningOp())
3941 return op->print(os, flags);
3942 // TODO: Improve BlockArgument print'ing.
3944 os <<
"<block argument> of type '" << arg.
getType()
3949 os <<
"<<NULL VALUE>>";
3953 if (
auto *op = getDefiningOp())
3954 return op->
print(os, state);
3958 os <<
"<block argument> of type '" << arg.
getType()
3963 print(llvm::errs());
3964 llvm::errs() <<
"\n";
3972 state.getImpl().getSSANameState().printValueID(*
this,
true,
3995 if (
auto result = llvm::dyn_cast<OpResult>(*
this)) {
3998 op = llvm::cast<BlockArgument>(*this).getOwner()->
getParentOp();
4000 os <<
"<<UNKNOWN SSA VALUE>>";
4006 printAsOperand(os, state);
4016 OperationPrinter printer(os, state.getImpl());
4017 if (!getParent() && !state.getPrinterFlags().shouldUseLocalScope()) {
4018 state.getImpl().initializeAliases(
this);
4019 printer.printTopLevelOperation(
this);
4021 printer.printFullOpWithIndentAndLoc(
this);
4027 llvm::errs() <<
"\n";
4032 llvm::errs() <<
"\n";
4038 os <<
"<<UNLINKED BLOCK>>\n";
4049 OperationPrinter(os, state.getImpl()).print(
this);
4058 os <<
"<<UNLINKED BLOCK>>\n";
4062 printAsOperand(os, state);
4065 OperationPrinter printer(os, state.getImpl());
4066 printer.printBlockName(
this);
4081 if (dimensions.empty())
4084 if (dimensions.empty())
4094 <<
"Failed parsing dimension list.";
4105 <<
"Failed parsing dimension list.";
4107 if (shapeArr.empty()) {
4109 <<
"Failed parsing dimension list. Did you mean an empty list? It "
4110 "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.
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 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 & 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 & printValueUsers(bool enable=true)
Print users of values as comments.
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 & useLocalScope(bool enable=true)
Use local scope when printing the operation.
std::optional< uint64_t > getLargeResourceStringLimit() const
Return the size limit in chars for printing large resources.
OpPrintingFlags & assumeVerified(bool enable=true)
Do not verify the operation when using custom operation printers.
OpPrintingFlags & skipRegions(bool skip=true)
Skip printing regions.
OpPrintingFlags & printUniqueSSAIDs(bool enable=true)
Print unique SSA ID numbers for values, block arguments and naming conflicts across all 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.