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/Regex.h"
47 #include "llvm/Support/SaveAndRestore.h"
48 #include "llvm/Support/Threading.h"
49 #include "llvm/Support/raw_ostream.h"
50 #include <type_traits>
58 #define DEBUG_TYPE "mlir-asm-printer"
78 [&]() {
return parseType(result.emplace_back()); });
94 auto &os = getStream();
98 *this << (operand ? operand.getType() : Type());
114 *this << (result ? result.getType() : Type());
126 #include "mlir/IR/OpAsmInterface.cpp.inc"
130 return entry.
emitError() <<
"unknown 'resource' key '" << entry.
getKey()
131 <<
"' for dialect '" << getDialect()->getNamespace()
143 struct AsmPrinterOptions {
144 llvm::cl::opt<int64_t> printElementsAttrWithHexIfLarger{
145 "mlir-print-elementsattrs-with-hex-if-larger",
147 "Print DenseElementsAttrs with a hex string that have "
148 "more elements than the given upper limit (use -1 to disable)")};
150 llvm::cl::opt<unsigned> elideElementsAttrIfLarger{
151 "mlir-elide-elementsattrs-if-larger",
152 llvm::cl::desc(
"Elide ElementsAttrs with \"...\" that have "
153 "more elements than the given upper limit")};
155 llvm::cl::opt<unsigned> elideResourceStringsIfLarger{
156 "mlir-elide-resource-strings-if-larger",
158 "Elide printing value of resources if string is too long in chars.")};
160 llvm::cl::opt<bool> printDebugInfoOpt{
161 "mlir-print-debuginfo", llvm::cl::init(
false),
162 llvm::cl::desc(
"Print debug info in MLIR output")};
164 llvm::cl::opt<bool> printPrettyDebugInfoOpt{
165 "mlir-pretty-debuginfo", llvm::cl::init(
false),
166 llvm::cl::desc(
"Print pretty debug info in MLIR output")};
170 llvm::cl::opt<bool> printGenericOpFormOpt{
171 "mlir-print-op-generic", llvm::cl::init(
false),
172 llvm::cl::desc(
"Print the generic op form"), llvm::cl::Hidden};
174 llvm::cl::opt<bool> assumeVerifiedOpt{
175 "mlir-print-assume-verified", llvm::cl::init(
false),
176 llvm::cl::desc(
"Skip op verification when using custom printers"),
179 llvm::cl::opt<bool> printLocalScopeOpt{
180 "mlir-print-local-scope", llvm::cl::init(
false),
181 llvm::cl::desc(
"Print with local scope and inline information (eliding "
182 "aliases for attributes, types, and locations")};
184 llvm::cl::opt<bool> skipRegionsOpt{
185 "mlir-print-skip-regions", llvm::cl::init(
false),
186 llvm::cl::desc(
"Skip regions when printing ops.")};
188 llvm::cl::opt<bool> printValueUsers{
189 "mlir-print-value-users", llvm::cl::init(
false),
191 "Print users of operation results and block arguments as a comment")};
195 static llvm::ManagedStatic<AsmPrinterOptions>
clOptions;
206 : printDebugInfoFlag(false), printDebugInfoPrettyFormFlag(false),
207 printGenericOpFormFlag(false), skipRegionsFlag(false),
208 assumeVerifiedFlag(false), printLocalScope(false),
209 printValueUsersFlag(false) {
213 if (
clOptions->elideElementsAttrIfLarger.getNumOccurrences())
214 elementsAttrElementLimit =
clOptions->elideElementsAttrIfLarger;
215 if (
clOptions->elideResourceStringsIfLarger.getNumOccurrences())
216 resourceStringCharLimit =
clOptions->elideResourceStringsIfLarger;
217 printDebugInfoFlag =
clOptions->printDebugInfoOpt;
218 printDebugInfoPrettyFormFlag =
clOptions->printPrettyDebugInfoOpt;
219 printGenericOpFormFlag =
clOptions->printGenericOpFormOpt;
220 assumeVerifiedFlag =
clOptions->assumeVerifiedOpt;
221 printLocalScope =
clOptions->printLocalScopeOpt;
222 skipRegionsFlag =
clOptions->skipRegionsOpt;
223 printValueUsersFlag =
clOptions->printValueUsers;
232 elementsAttrElementLimit = largeElementLimit;
238 resourceStringCharLimit = largeResourceLimit;
246 printDebugInfoFlag = enable;
247 printDebugInfoPrettyFormFlag = prettyForm;
253 printGenericOpFormFlag = enable;
259 skipRegionsFlag = skip;
265 assumeVerifiedFlag =
true;
273 printLocalScope =
true;
279 printValueUsersFlag =
true;
285 return elementsAttrElementLimit &&
286 *elementsAttrElementLimit < int64_t(attr.getNumElements()) &&
287 !llvm::isa<SplatElementsAttr>(attr);
292 return elementsAttrElementLimit;
297 return resourceStringCharLimit;
302 return printDebugInfoFlag;
307 return printDebugInfoPrettyFormFlag;
312 return printGenericOpFormFlag;
320 return assumeVerifiedFlag;
328 return printValueUsersFlag;
336 if (
clOptions->printElementsAttrWithHexIfLarger.getNumOccurrences()) {
338 if (
clOptions->printElementsAttrWithHexIfLarger == -1)
340 return numElements >
clOptions->printElementsAttrWithHexIfLarger;
345 return numElements > 100;
356 struct NewLineCounter {
357 unsigned curLine = 1;
360 static raw_ostream &
operator<<(raw_ostream &os, NewLineCounter &newLine) {
379 template <
typename Container,
typename UnaryFunctor>
381 llvm::interleaveComma(c,
os, eachFn);
427 function_ref<
void(
unsigned,
bool)> printValueName =
nullptr);
440 bool withKeyword =
false);
444 bool isTopLevel =
false);
480 function_ref<
void(
unsigned,
bool)> printValueName =
nullptr);
504 SymbolAlias(StringRef name, uint32_t suffixIndex,
bool isType,
506 : name(name), suffixIndex(suffixIndex), isType(isType),
507 isDeferrable(isDeferrable) {}
510 void print(raw_ostream &os)
const {
511 os << (isType ?
"!" :
"#") << name;
517 bool isTypeAlias()
const {
return isType; }
520 bool canBeDeferred()
const {
return isDeferrable; }
526 uint32_t suffixIndex : 30;
530 bool isDeferrable : 1;
536 class AliasInitializer {
540 llvm::BumpPtrAllocator &aliasAllocator)
541 : interfaces(interfaces), aliasAllocator(aliasAllocator),
542 aliasOS(aliasBuffer) {}
545 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias);
553 std::pair<size_t, size_t>
visit(
Attribute attr,
bool canBeDeferred =
false,
554 bool elideType =
false) {
555 return visitImpl(attr, aliases, canBeDeferred, elideType);
562 std::pair<size_t, size_t>
visit(
Type type,
bool canBeDeferred =
false) {
563 return visitImpl(type, aliases, canBeDeferred);
567 struct InProgressAliasInfo {
568 InProgressAliasInfo()
569 : aliasDepth(0), isType(false), canBeDeferred(false) {}
570 InProgressAliasInfo(StringRef alias,
bool isType,
bool canBeDeferred)
571 : alias(alias), aliasDepth(1), isType(isType),
572 canBeDeferred(canBeDeferred) {}
574 bool operator<(
const InProgressAliasInfo &rhs)
const {
576 if (aliasDepth != rhs.aliasDepth)
577 return aliasDepth < rhs.aliasDepth;
578 if (isType != rhs.isType)
580 return alias < rhs.alias;
585 std::optional<StringRef> alias;
588 unsigned aliasDepth : 30;
592 bool canBeDeferred : 1;
602 template <
typename T,
typename... PrintArgs>
603 std::pair<size_t, size_t>
605 llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
606 bool canBeDeferred, PrintArgs &&...printArgs);
609 void markAliasNonDeferrable(
size_t aliasIndex);
613 template <
typename T>
614 void generateAlias(T symbol, InProgressAliasInfo &alias,
bool canBeDeferred);
618 static void initializeAliases(
619 llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
620 llvm::MapVector<const void *, SymbolAlias> &symbolToAlias);
626 llvm::BumpPtrAllocator &aliasAllocator;
629 llvm::MapVector<const void *, InProgressAliasInfo> aliases;
633 llvm::raw_svector_ostream aliasOS;
641 class DummyAliasOperationPrinter :
private OpAsmPrinter {
643 explicit DummyAliasOperationPrinter(
const OpPrintingFlags &printerFlags,
644 AliasInitializer &initializer)
645 : printerFlags(printerFlags), initializer(initializer) {}
649 void printCustomOrGenericOp(
Operation *op)
override {
651 if (printerFlags.shouldPrintDebugInfo())
652 initializer.visit(op->
getLoc(),
true);
655 if (!printerFlags.shouldPrintGenericOpForm()) {
666 void printGenericOp(
Operation *op,
bool printOpName =
true)
override {
668 if (!printerFlags.shouldSkipRegions()) {
682 printAttribute(attr.getValue());
688 void print(
Block *block,
bool printBlockArgs =
true,
689 bool printBlockTerminator =
true) {
692 if (printBlockArgs) {
697 if (printerFlags.shouldPrintDebugInfo())
699 initializer.visit(arg.getLoc(),
false);
707 auto range = llvm::make_range(
709 std::prev(block->
end(),
710 (!hasTerminator || printBlockTerminator) ? 0 : 1));
712 printCustomOrGenericOp(&op);
717 bool printBlockTerminators,
718 bool printEmptyBlock =
false)
override {
721 if (printerFlags.shouldSkipRegions()) {
726 auto *entryBlock = ®ion.
front();
727 print(entryBlock, printEntryBlockArgs, printBlockTerminators);
728 for (
Block &b : llvm::drop_begin(region, 1))
733 bool omitType)
override {
736 if (printerFlags.shouldPrintDebugInfo())
738 initializer.visit(arg.
getLoc(),
false);
742 void printType(
Type type)
override { initializer.visit(type); }
745 void printAttribute(
Attribute attr)
override { initializer.visit(attr); }
746 void printAttributeWithoutType(
Attribute attr)
override {
747 printAttribute(attr);
750 initializer.visit(attr);
754 initializer.visit(type);
759 void printOptionalLocationSpecifier(
Location loc)
override {
769 if (elidedAttrs.empty()) {
771 printAttribute(attr.getValue());
774 llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
777 if (!elidedAttrsSet.contains(attr.getName().strref()))
778 printAttribute(attr.getValue());
780 void printOptionalAttrDictWithKeyword(
783 printOptionalAttrDict(attrs, elidedAttrs);
788 raw_ostream &getStream()
const override {
return os; }
792 void printFloat(
const APFloat &)
override {}
793 void printAffineMapOfSSAIds(AffineMapAttr,
ValueRange)
override {}
796 void increaseIndent()
override {}
797 void decreaseIndent()
override {}
798 void printOperand(
Value)
override {}
799 void printOperand(
Value, raw_ostream &os)
override {
808 void printSymbolName(StringRef)
override {}
809 void printSuccessor(
Block *)
override {}
817 AliasInitializer &initializer;
820 mutable llvm::raw_null_ostream os;
825 explicit DummyAliasDialectAsmPrinter(AliasInitializer &initializer,
828 : initializer(initializer), canBeDeferred(canBeDeferred),
829 childIndices(childIndices) {}
834 template <
typename T,
typename... PrintArgs>
835 size_t printAndVisitNestedAliases(T value, PrintArgs &&...printArgs) {
836 printAndVisitNestedAliasesImpl(value, printArgs...);
837 return maxAliasDepth;
843 void printAndVisitNestedAliasesImpl(
Attribute attr,
bool elideType) {
844 if (!isa<BuiltinDialect>(attr.
getDialect())) {
848 }
else if (llvm::isa<AffineMapAttr, DenseArrayAttr, FloatAttr, IntegerAttr,
849 IntegerSetAttr, UnitAttr>(attr)) {
851 }
else if (
auto distinctAttr = dyn_cast<DistinctAttr>(attr)) {
852 printAttribute(distinctAttr.getReferencedAttr());
853 }
else if (
auto dictAttr = dyn_cast<DictionaryAttr>(attr)) {
855 printAttribute(nestedAttr.getName());
856 printAttribute(nestedAttr.getValue());
858 }
else if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr)) {
859 for (
Attribute nestedAttr : arrayAttr.getValue())
860 printAttribute(nestedAttr);
861 }
else if (
auto typeAttr = dyn_cast<TypeAttr>(attr)) {
863 }
else if (
auto locAttr = dyn_cast<OpaqueLoc>(attr)) {
864 printAttribute(locAttr.getFallbackLocation());
865 }
else if (
auto locAttr = dyn_cast<NameLoc>(attr)) {
866 if (!isa<UnknownLoc>(locAttr.getChildLoc()))
867 printAttribute(locAttr.getChildLoc());
868 }
else if (
auto locAttr = dyn_cast<CallSiteLoc>(attr)) {
869 printAttribute(locAttr.getCallee());
870 printAttribute(locAttr.getCaller());
871 }
else if (
auto locAttr = dyn_cast<FusedLoc>(attr)) {
872 if (
Attribute metadata = locAttr.getMetadata())
873 printAttribute(metadata);
874 for (
Location nestedLoc : locAttr.getLocations())
875 printAttribute(nestedLoc);
880 if (
auto typedAttr = llvm::dyn_cast<TypedAttr>(attr)) {
881 Type attrType = typedAttr.getType();
882 if (!llvm::isa<NoneType>(attrType))
887 void printAndVisitNestedAliasesImpl(
Type type) {
892 if (
auto memrefTy = llvm::dyn_cast<MemRefType>(type)) {
894 MemRefLayoutAttrInterface layout = memrefTy.getLayout();
895 if (!llvm::isa<AffineMapAttr>(layout) || !layout.isIdentity())
896 printAttribute(memrefTy.getLayout());
897 if (memrefTy.getMemorySpace())
898 printAttribute(memrefTy.getMemorySpace());
903 auto visitFn = [&](
auto element) {
905 (void)printAlias(element);
912 recordAliasResult(initializer.visit(type, canBeDeferred));
916 void printAttribute(
Attribute attr)
override {
917 recordAliasResult(initializer.visit(attr, canBeDeferred));
919 void printAttributeWithoutType(
Attribute attr)
override {
921 initializer.visit(attr, canBeDeferred,
true));
924 printAttribute(attr);
933 void recordAliasResult(std::pair<size_t, size_t> aliasDepthAndIndex) {
934 childIndices.push_back(aliasDepthAndIndex.second);
935 if (aliasDepthAndIndex.first > maxAliasDepth)
936 maxAliasDepth = aliasDepthAndIndex.first;
941 raw_ostream &getStream()
const override {
return os; }
945 void printFloat(
const APFloat &)
override {}
948 void printSymbolName(StringRef)
override {}
951 LogicalResult pushCyclicPrinting(
const void *opaquePointer)
override {
952 return success(cyclicPrintingStack.insert(opaquePointer));
955 void popCyclicPrinting()
override { cyclicPrintingStack.pop_back(); }
962 AliasInitializer &initializer;
971 size_t maxAliasDepth = 0;
974 mutable llvm::raw_null_ostream os;
982 StringRef allowedPunctChars =
"$._-",
983 bool allowTrailingDigit =
true) {
984 assert(!name.empty() &&
"Shouldn't have an empty name here");
986 auto copyNameToBuffer = [&] {
987 for (
char ch : name) {
988 if (llvm::isAlnum(ch) || allowedPunctChars.contains(ch))
989 buffer.push_back(ch);
991 buffer.push_back(
'_');
993 buffer.append(llvm::utohexstr((
unsigned char)ch));
1000 if (isdigit(name[0])) {
1001 buffer.push_back(
'_');
1008 if (!allowTrailingDigit && isdigit(name.back())) {
1010 buffer.push_back(
'_');
1015 for (
char ch : name) {
1016 if (!llvm::isAlnum(ch) && !allowedPunctChars.contains(ch)) {
1028 void AliasInitializer::initializeAliases(
1029 llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
1030 llvm::MapVector<const void *, SymbolAlias> &symbolToAlias) {
1032 unprocessedAliases = visitedSymbols.takeVector();
1033 llvm::stable_sort(unprocessedAliases, [](
const auto &lhs,
const auto &rhs) {
1034 return lhs.second < rhs.second;
1037 llvm::StringMap<unsigned> nameCounts;
1038 for (
auto &[symbol, aliasInfo] : unprocessedAliases) {
1039 if (!aliasInfo.alias)
1041 StringRef alias = *aliasInfo.alias;
1042 unsigned nameIndex = nameCounts[alias]++;
1043 symbolToAlias.insert(
1044 {symbol, SymbolAlias(alias, nameIndex, aliasInfo.isType,
1045 aliasInfo.canBeDeferred)});
1049 void AliasInitializer::initialize(
1051 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias) {
1055 DummyAliasOperationPrinter aliasPrinter(printerFlags, *
this);
1056 aliasPrinter.printCustomOrGenericOp(op);
1059 initializeAliases(aliases, attrTypeToAlias);
1062 template <
typename T,
typename... PrintArgs>
1063 std::pair<size_t, size_t> AliasInitializer::visitImpl(
1064 T value, llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
1065 bool canBeDeferred, PrintArgs &&...printArgs) {
1066 auto [it, inserted] =
1067 aliases.insert({value.getAsOpaquePointer(), InProgressAliasInfo()});
1068 size_t aliasIndex = std::distance(aliases.begin(), it);
1072 markAliasNonDeferrable(aliasIndex);
1073 return {
static_cast<size_t>(it->second.aliasDepth), aliasIndex};
1077 generateAlias(value, it->second, canBeDeferred);
1081 DummyAliasDialectAsmPrinter printer(*
this, canBeDeferred, childAliases);
1082 size_t maxAliasDepth =
1083 printer.printAndVisitNestedAliases(value, printArgs...);
1086 it = std::next(aliases.begin(), aliasIndex);
1089 it->second.childIndices = std::move(childAliases);
1091 it->second.aliasDepth = maxAliasDepth + 1;
1094 return {(size_t)it->second.aliasDepth, aliasIndex};
1097 void AliasInitializer::markAliasNonDeferrable(
size_t aliasIndex) {
1098 auto *it = std::next(aliases.begin(), aliasIndex);
1102 if (!it->second.canBeDeferred)
1105 it->second.canBeDeferred =
false;
1108 for (
size_t childIndex : it->second.childIndices)
1109 markAliasNonDeferrable(childIndex);
1112 template <
typename T>
1113 void AliasInitializer::generateAlias(T symbol, InProgressAliasInfo &alias,
1114 bool canBeDeferred) {
1116 for (
const auto &interface : interfaces) {
1118 interface.getAlias(symbol, aliasOS);
1121 nameBuffer = std::move(aliasBuffer);
1122 assert(!nameBuffer.empty() &&
"expected valid alias name");
1127 if (nameBuffer.empty())
1134 name = name.copy(aliasAllocator);
1135 alias = InProgressAliasInfo(name, std::is_base_of_v<Type, T>,
1162 void printNonDeferredAliases(
AsmPrinter::Impl &p, NewLineCounter &newLine) {
1163 printAliases(p, newLine,
false);
1168 printAliases(p, newLine,
true);
1178 llvm::MapVector<const void *, SymbolAlias> attrTypeToAlias;
1181 llvm::BumpPtrAllocator aliasAllocator;
1185 void AliasState::initialize(
1188 AliasInitializer initializer(interfaces, aliasAllocator);
1189 initializer.initialize(op, printerFlags, attrTypeToAlias);
1194 if (it == attrTypeToAlias.end())
1196 it->second.print(os);
1202 if (it == attrTypeToAlias.end())
1205 it->second.print(os);
1209 void AliasState::printAliases(
AsmPrinter::Impl &p, NewLineCounter &newLine,
1211 auto filterFn = [=](
const auto &aliasIt) {
1212 return aliasIt.second.canBeDeferred() == isDeferred;
1214 for (
auto &[opaqueSymbol, alias] :
1215 llvm::make_filter_range(attrTypeToAlias, filterFn)) {
1219 if (alias.isTypeAlias()) {
1252 class SSANameState {
1255 enum :
unsigned { NameSentinel = ~0U };
1258 SSANameState() =
default;
1263 void printValueID(
Value value,
bool printResultNo, raw_ostream &stream)
const;
1266 void printOperationID(
Operation *op, raw_ostream &stream)
const;
1273 BlockInfo getBlockInfo(
Block *block);
1282 void numberValuesInRegion(
Region ®ion);
1283 void numberValuesInBlock(
Block &block);
1290 void getResultIDAndNumber(
OpResult result,
Value &lookupValue,
1291 std::optional<int> &lookupResultNo)
const;
1294 void setValueName(
Value value, StringRef name);
1298 StringRef uniqueValueName(StringRef name);
1321 llvm::ScopedHashTable<StringRef, char> usedNames;
1322 llvm::BumpPtrAllocator usedNameAllocator;
1325 unsigned nextValueID = 0;
1327 unsigned nextArgumentID = 0;
1329 unsigned nextConflictID = 0;
1338 : printerFlags(printerFlags) {
1339 llvm::SaveAndRestore valueIDSaver(nextValueID);
1340 llvm::SaveAndRestore argumentIDSaver(nextArgumentID);
1341 llvm::SaveAndRestore conflictIDSaver(nextConflictID);
1346 using UsedNamesScopeTy = llvm::ScopedHashTable<StringRef, char>::ScopeTy;
1347 using NamingContext =
1348 std::tuple<Region *, unsigned, unsigned, unsigned, UsedNamesScopeTy *>;
1351 llvm::BumpPtrAllocator allocator;
1354 auto *topLevelNamesScope =
1355 new (allocator.Allocate<UsedNamesScopeTy>()) UsedNamesScopeTy(usedNames);
1359 nameContext.push_back(std::make_tuple(®ion, nextValueID, nextArgumentID,
1360 nextConflictID, topLevelNamesScope));
1362 numberValuesInOp(*op);
1364 while (!nameContext.empty()) {
1366 UsedNamesScopeTy *parentScope;
1367 std::tie(region, nextValueID, nextArgumentID, nextConflictID, parentScope) =
1368 nameContext.pop_back_val();
1372 while (usedNames.getCurScope() != parentScope) {
1373 usedNames.getCurScope()->~UsedNamesScopeTy();
1374 assert((usedNames.getCurScope() !=
nullptr || parentScope ==
nullptr) &&
1375 "top level parentScope must be a nullptr");
1379 auto *curNamesScope =
new (allocator.Allocate<UsedNamesScopeTy>())
1380 UsedNamesScopeTy(usedNames);
1382 numberValuesInRegion(*region);
1386 nameContext.push_back(std::make_tuple(®ion, nextValueID,
1387 nextArgumentID, nextConflictID,
1392 while (usedNames.getCurScope() !=
nullptr)
1393 usedNames.getCurScope()->~UsedNamesScopeTy();
1396 void SSANameState::printValueID(
Value value,
bool printResultNo,
1397 raw_ostream &stream)
const {
1399 stream <<
"<<NULL VALUE>>";
1403 std::optional<int> resultNo;
1404 auto lookupValue = value;
1408 if (
OpResult result = dyn_cast<OpResult>(value))
1409 getResultIDAndNumber(result, lookupValue, resultNo);
1411 auto it = valueIDs.find(lookupValue);
1412 if (it == valueIDs.end()) {
1413 stream <<
"<<UNKNOWN SSA VALUE>>";
1418 if (it->second != NameSentinel) {
1419 stream << it->second;
1421 auto nameIt = valueNames.find(lookupValue);
1422 assert(nameIt != valueNames.end() &&
"Didn't have a name entry?");
1423 stream << nameIt->second;
1426 if (resultNo && printResultNo)
1427 stream <<
'#' << *resultNo;
1430 void SSANameState::printOperationID(
Operation *op, raw_ostream &stream)
const {
1431 auto it = operationIDs.find(op);
1432 if (it == operationIDs.end()) {
1433 stream <<
"<<UNKNOWN OPERATION>>";
1435 stream <<
'%' << it->second;
1440 auto it = opResultGroups.find(op);
1441 return it == opResultGroups.end() ?
ArrayRef<int>() : it->second;
1444 BlockInfo SSANameState::getBlockInfo(
Block *block) {
1445 auto it = blockNames.find(block);
1446 BlockInfo invalidBlock{-1,
"INVALIDBLOCK"};
1447 return it != blockNames.end() ? it->second : invalidBlock;
1450 void SSANameState::shadowRegionArgs(
Region ®ion,
ValueRange namesToUse) {
1451 assert(!region.
empty() &&
"cannot shadow arguments of an empty region");
1453 "incorrect number of names passed in");
1455 "only KnownIsolatedFromAbove ops can shadow names");
1458 for (
unsigned i = 0, e = namesToUse.size(); i != e; ++i) {
1459 auto nameToUse = namesToUse[i];
1460 if (nameToUse ==
nullptr)
1465 llvm::raw_svector_ostream nameStream(nameStr);
1466 printValueID(nameToUse,
true, nameStream);
1469 assert(valueIDs[nameToReplace] == NameSentinel);
1472 auto name = StringRef(nameStream.str()).drop_front();
1475 valueNames[nameToReplace] = name.copy(usedNameAllocator);
1479 void SSANameState::numberValuesInRegion(
Region ®ion) {
1480 auto setBlockArgNameFn = [&](
Value arg, StringRef name) {
1481 assert(!valueIDs.count(arg) &&
"arg numbered multiple times");
1482 assert(llvm::cast<BlockArgument>(arg).getOwner()->getParent() == ®ion &&
1483 "arg not defined in current region");
1484 setValueName(arg, name);
1489 if (
auto asmInterface = dyn_cast<OpAsmOpInterface>(op))
1490 asmInterface.getAsmBlockArgumentNames(region, setBlockArgNameFn);
1495 unsigned nextBlockID = 0;
1496 for (
auto &block : region) {
1499 auto blockInfoIt = blockNames.insert({&block, {-1,
""}});
1500 if (blockInfoIt.second) {
1504 llvm::raw_string_ostream(name) <<
"^bb" << nextBlockID;
1505 blockInfoIt.first->second.name = StringRef(name).copy(usedNameAllocator);
1507 blockInfoIt.first->second.ordering = nextBlockID++;
1509 numberValuesInBlock(block);
1513 void SSANameState::numberValuesInBlock(
Block &block) {
1518 llvm::raw_svector_ostream specialName(specialNameBuffer);
1520 if (valueIDs.count(arg))
1523 specialNameBuffer.resize(strlen(
"arg"));
1524 specialName << nextArgumentID++;
1526 setValueName(arg, specialName.str());
1530 for (
auto &op : block)
1531 numberValuesInOp(op);
1534 void SSANameState::numberValuesInOp(
Operation &op) {
1537 auto setResultNameFn = [&](
Value result, StringRef name) {
1538 assert(!valueIDs.count(result) &&
"result numbered multiple times");
1539 assert(result.
getDefiningOp() == &op &&
"result not defined by 'op'");
1540 setValueName(result, name);
1543 if (
int resultNo = llvm::cast<OpResult>(result).getResultNumber())
1544 resultGroups.push_back(resultNo);
1547 auto setBlockNameFn = [&](
Block *block, StringRef name) {
1549 "getAsmBlockArgumentNames callback invoked on a block not directly "
1550 "nested under the current operation");
1551 assert(!blockNames.count(block) &&
"block numbered multiple times");
1554 if (name.data() != tmpBuffer.data()) {
1555 tmpBuffer.append(name);
1556 name = tmpBuffer.str();
1558 name = name.copy(usedNameAllocator);
1559 blockNames[block] = {-1, name};
1563 if (OpAsmOpInterface asmInterface = dyn_cast<OpAsmOpInterface>(&op)) {
1564 asmInterface.getAsmBlockNames(setBlockNameFn);
1565 asmInterface.getAsmResultNames(setResultNameFn);
1570 if (numResults == 0) {
1573 if (operationIDs.try_emplace(&op, nextValueID).second)
1581 if (valueIDs.try_emplace(resultBegin, nextValueID).second)
1585 if (resultGroups.size() != 1) {
1586 llvm::array_pod_sort(resultGroups.begin(), resultGroups.end());
1587 opResultGroups.try_emplace(&op, std::move(resultGroups));
1591 void SSANameState::getResultIDAndNumber(
1593 std::optional<int> &lookupResultNo)
const {
1601 auto resultGroupIt = opResultGroups.find(owner);
1602 if (resultGroupIt == opResultGroups.end()) {
1604 lookupResultNo = resultNo;
1611 const auto *it = llvm::upper_bound(resultGroups, resultNo);
1612 int groupResultNo = 0, groupSize = 0;
1615 if (it == resultGroups.end()) {
1616 groupResultNo = resultGroups.back();
1617 groupSize =
static_cast<int>(owner->
getNumResults()) - resultGroups.back();
1620 groupResultNo = *std::prev(it);
1621 groupSize = *it - groupResultNo;
1626 lookupResultNo = resultNo - groupResultNo;
1627 lookupValue = owner->
getResult(groupResultNo);
1630 void SSANameState::setValueName(
Value value, StringRef name) {
1633 valueIDs[value] = nextValueID++;
1637 valueIDs[value] = NameSentinel;
1638 valueNames[value] = uniqueValueName(name);
1641 StringRef SSANameState::uniqueValueName(StringRef name) {
1646 if (!usedNames.count(name)) {
1647 name = name.copy(usedNameAllocator);
1653 probeName.push_back(
'_');
1655 probeName += llvm::utostr(nextConflictID++);
1656 if (!usedNames.count(probeName)) {
1657 name = probeName.str().copy(usedNameAllocator);
1660 probeName.resize(name.size() + 1);
1664 usedNames.insert(name,
char());
1674 class DistinctState {
1680 uint64_t distinctCounter = 0;
1685 uint64_t DistinctState::getId(
DistinctAttr distinctAttr) {
1686 auto [it, inserted] =
1687 distinctAttrMap.try_emplace(distinctAttr, distinctCounter);
1690 return it->getSecond();
1697 AsmParsedResourceEntry::~AsmParsedResourceEntry() =
default;
1698 AsmResourceBuilder::~AsmResourceBuilder() =
default;
1699 AsmResourceParser::~AsmResourceParser() =
default;
1700 AsmResourcePrinter::~AsmResourcePrinter() =
default;
1704 case AsmResourceEntryKind::Blob:
1706 case AsmResourceEntryKind::Bool:
1708 case AsmResourceEntryKind::String:
1711 llvm_unreachable(
"unknown AsmResourceEntryKind");
1715 std::unique_ptr<ResourceCollection> &collection = keyToResources[key.str()];
1717 collection = std::make_unique<ResourceCollection>(key);
1721 std::vector<std::unique_ptr<AsmResourcePrinter>>
1723 std::vector<std::unique_ptr<AsmResourcePrinter>> printers;
1724 for (
auto &it : keyToResources) {
1725 ResourceCollection *collection = it.second.get();
1727 return collection->buildResources(op, builder);
1729 printers.emplace_back(
1735 LogicalResult FallbackAsmResourceMap::ResourceCollection::parseResource(
1742 resources.emplace_back(entry.
getKey(), std::move(*blob));
1749 resources.emplace_back(entry.
getKey(), *value);
1756 resources.emplace_back(entry.
getKey(), std::move(*str));
1763 void FallbackAsmResourceMap::ResourceCollection::buildResources(
1765 for (
const auto &entry : resources) {
1766 if (
const auto *value = std::get_if<AsmResourceBlob>(&entry.value))
1768 else if (
const auto *value = std::get_if<bool>(&entry.value))
1770 else if (
const auto *value = std::get_if<std::string>(&entry.value))
1773 llvm_unreachable(
"unknown AsmResourceEntryKind");
1787 : interfaces(op->
getContext()), nameState(op, printerFlags),
1788 printerFlags(printerFlags), locationMap(locationMap) {}
1791 : interfaces(ctx), printerFlags(printerFlags), locationMap(locationMap) {}
1795 aliasState.initialize(op, printerFlags, interfaces);
1815 return llvm::make_pointee_range(externalResourcePrinters);
1825 (*locationMap)[op] = std::make_pair(line, col);
1831 return dialectResources;
1835 return success(cyclicPrintingStack.insert(opaquePointer));
1851 AliasState aliasState;
1854 SSANameState nameState;
1857 DistinctState distinctState;
1873 template <
typename Range>
1877 [&stream](
const auto &dimSize) {
1878 if (ShapedType::isDynamic(dimSize))
1896 return printerFlags;
1900 auto parentThreadId = llvm::get_threadid();
1902 if (parentThreadId == llvm::get_threadid()) {
1904 diag.print(llvm::dbgs());
1905 llvm::dbgs() <<
"\n";
1912 LLVM_DEBUG(llvm::dbgs()
1914 <<
"' failed to verify and will be printed in generic form\n");
1918 return printerFlags;
1937 return impl->getPrinterFlags();
1941 std::unique_ptr<AsmResourcePrinter> printer) {
1942 impl->externalResourcePrinters.emplace_back(std::move(printer));
1947 return impl->getDialectResources();
1955 : os(os), state(state), printerFlags(state.getPrinterFlags()) {}
1963 printLocation(loc, allowAlias);
1969 if (!isTopLevel &&
succeeded(state.getAliasState().getAlias(loc, os)))
1973 .Case<OpaqueLoc>([&](OpaqueLoc loc) {
1974 printLocationInternal(loc.getFallbackLocation(), pretty);
1976 .Case<UnknownLoc>([&](UnknownLoc loc) {
1982 .Case<FileLineColLoc>([&](FileLineColLoc loc) {
1984 os << loc.getFilename().getValue();
1986 printEscapedString(loc.getFilename());
1987 os <<
':' << loc.getLine() <<
':' << loc.getColumn();
1989 .Case<NameLoc>([&](NameLoc loc) {
1990 printEscapedString(loc.getName());
1993 auto childLoc = loc.getChildLoc();
1994 if (!llvm::isa<UnknownLoc>(childLoc)) {
1996 printLocationInternal(childLoc, pretty);
2000 .Case<CallSiteLoc>([&](CallSiteLoc loc) {
2005 printLocationInternal(callee, pretty);
2007 if (llvm::isa<NameLoc>(callee)) {
2008 if (llvm::isa<FileLineColLoc>(caller)) {
2011 os << newLine <<
" at ";
2014 os << newLine <<
" at ";
2019 printLocationInternal(caller, pretty);
2023 .Case<FusedLoc>([&](
FusedLoc loc) {
2026 if (
Attribute metadata = loc.getMetadata()) {
2034 [&](Location loc) { printLocationInternal(loc, pretty); },
2035 [&]() { os << ", "; });
2042 static void printFloatValue(const APFloat &apValue, raw_ostream &os) {
2043 // We would like to output the FP constant value in exponential notation,
2044 // but we cannot do this if doing so will lose precision. Check here to
2045 // make sure that we only output it in exponential format if we can parse
2046 // the value back and get the same value.
2047 bool isInf = apValue.isInfinity();
2048 bool isNaN = apValue.isNaN();
2049 if (!isInf && !isNaN) {
2050 SmallString<128> strValue;
2051 apValue.toString(strValue, /*FormatPrecision=*/6, /*FormatMaxPadding=*/0,
2052 /*TruncateZero=*/false);
2054 // Check to make sure that the stringized number is not some string like
2055 // "Inf" or NaN, that atof will accept, but the lexer will not. Check
2056 // that the string matches the "[-+]?[0-9]" regex.
2057 assert(((strValue[0] >= '0
' && strValue[0] <= '9') ||
2058 ((strValue[0] ==
'-' || strValue[0] ==
'+') &&
2059 (strValue[1] >=
'0' && strValue[1] <=
'9'))) &&
2060 "[-+]?[0-9] regex does not match!");
2064 if (APFloat(apValue.getSemantics(), strValue).bitwiseIsEqual(apValue)) {
2072 apValue.toString(strValue);
2075 if (strValue.str().contains(
'.')) {
2084 APInt apInt = apValue.bitcastToAPInt();
2085 apInt.toString(str, 16,
false,
2092 return printLocationInternal(loc,
true,
true);
2096 printLocationInternal(loc,
false,
true);
2104 state.getDialectResources()[resource.
getDialect()].insert(resource);
2112 if (symName.empty() || !isalpha(symName.front()))
2117 symName = symName.drop_while(
2118 [](
char c) {
return llvm::isAlnum(c) || c ==
'.' || c ==
'_'; });
2119 if (symName.empty())
2124 return symName.front() ==
'<' && symName.back() ==
'>';
2129 StringRef dialectName, StringRef symString) {
2130 os << symPrefix << dialectName;
2135 os <<
'.' << symString;
2139 os << '<' << symString << '>
';
2143 static bool isBareIdentifier(StringRef name) {
2144 // By making this unsigned, the value passed in to isalnum will always be
2145 // in the range 0-255. This is important when building with MSVC because
2146 // its implementation will assert. This situation can arise when dealing
2147 // with UTF-8 multibyte characters.
2148 if (name.empty() || (!isalpha(name[0]) && name[0] != '_
'))
2150 return llvm::all_of(name.drop_front(), [](unsigned char c) {
2151 return isalnum(c) || c == '_
' || c == '$
' || c == '.
';
2157 static void printKeywordOrString(StringRef keyword, raw_ostream &os) {
2158 // If it can be represented as a bare identifier, write it directly.
2159 if (isBareIdentifier(keyword)) {
2164 // Otherwise, output the keyword wrapped in quotes with proper escaping.
2166 printEscapedString(keyword, os);
2173 static void printSymbolReference(StringRef symbolRef, raw_ostream &os) {
2174 if (symbolRef.empty()) {
2175 os << "@<<INVALID EMPTY SYMBOL>>
";
2179 printKeywordOrString(symbolRef, os);
2182 // Print out a valid ElementsAttr that is succinct and can represent any
2183 // potential shape/type, for use when eliding a large ElementsAttr.
2185 // We choose to use a dense resource ElementsAttr literal with conspicuous
2186 // content to hopefully alert readers to the fact that this has been elided.
2187 static void printElidedElementsAttr(raw_ostream &os) {
2188 os << R"(dense_resource<__elided__>)
";
2191 LogicalResult AsmPrinter::Impl::printAlias(Attribute attr) {
2192 return state.getAliasState().getAlias(attr, os);
2195 LogicalResult AsmPrinter::Impl::printAlias(Type type) {
2196 return state.getAliasState().getAlias(type, os);
2199 void AsmPrinter::Impl::printAttribute(Attribute attr,
2200 AttrTypeElision typeElision) {
2202 os << "<<NULL ATTRIBUTE>>
";
2206 // Try to print an alias for this attribute.
2207 if (succeeded(printAlias(attr)))
2209 return printAttributeImpl(attr, typeElision);
2212 void AsmPrinter::Impl::printAttributeImpl(Attribute attr,
2213 AttrTypeElision typeElision) {
2214 if (!isa<BuiltinDialect>(attr.getDialect())) {
2215 printDialectAttribute(attr);
2216 } else if (auto opaqueAttr = llvm::dyn_cast<OpaqueAttr>(attr)) {
2217 printDialectSymbol(os, "#
", opaqueAttr.getDialectNamespace(),
2218 opaqueAttr.getAttrData());
2219 } else if (llvm::isa<UnitAttr>(attr)) {
2222 } else if (auto distinctAttr = llvm::dyn_cast<DistinctAttr>(attr)) {
2223 os << "distinct[
" << state.getDistinctState().getId(distinctAttr) << "]<
";
2224 if (!llvm::isa<UnitAttr>(distinctAttr.getReferencedAttr())) {
2225 printAttribute(distinctAttr.getReferencedAttr());
2229 } else if (auto dictAttr = llvm::dyn_cast<DictionaryAttr>(attr)) {
2231 interleaveComma(dictAttr.getValue(),
2232 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2235 } else if (auto intAttr = llvm::dyn_cast<IntegerAttr>(attr)) {
2236 Type intType = intAttr.getType();
2237 if (intType.isSignlessInteger(1)) {
2238 os << (intAttr.getValue().getBoolValue() ? "true" : "false");
2240 // Boolean integer attributes always elides the type.
2244 // Only print attributes as unsigned if they are explicitly unsigned or are
2245 // signless 1-bit values. Indexes, signed values, and multi-bit signless
2246 // values print as signed.
2248 intType.isUnsignedInteger() || intType.isSignlessInteger(1);
2249 intAttr.getValue().print(os, !isUnsigned);
2251 // IntegerAttr elides the type if I64.
2252 if (typeElision == AttrTypeElision::May && intType.isSignlessInteger(64))
2255 } else if (auto floatAttr = llvm::dyn_cast<FloatAttr>(attr)) {
2256 printFloatValue(floatAttr.getValue(), os);
2258 // FloatAttr elides the type if F64.
2259 if (typeElision == AttrTypeElision::May && floatAttr.getType().isF64())
2262 } else if (auto strAttr = llvm::dyn_cast<StringAttr>(attr)) {
2263 printEscapedString(strAttr.getValue());
2265 } else if (auto arrayAttr = llvm::dyn_cast<ArrayAttr>(attr)) {
2267 interleaveComma(arrayAttr.getValue(), [&](Attribute attr) {
2268 printAttribute(attr, AttrTypeElision::May);
2272 } else if (auto affineMapAttr = llvm::dyn_cast<AffineMapAttr>(attr)) {
2273 os << "affine_map<
";
2274 affineMapAttr.getValue().print(os);
2277 // AffineMap always elides the type.
2280 } else if (auto integerSetAttr = llvm::dyn_cast<IntegerSetAttr>(attr)) {
2281 os << "affine_set<
";
2282 integerSetAttr.getValue().print(os);
2285 // IntegerSet always elides the type.
2288 } else if (auto typeAttr = llvm::dyn_cast<TypeAttr>(attr)) {
2289 printType(typeAttr.getValue());
2291 } else if (auto refAttr = llvm::dyn_cast<SymbolRefAttr>(attr)) {
2292 printSymbolReference(refAttr.getRootReference().getValue(), os);
2293 for (FlatSymbolRefAttr nestedRef : refAttr.getNestedReferences()) {
2295 printSymbolReference(nestedRef.getValue(), os);
2298 } else if (auto intOrFpEltAttr =
2299 llvm::dyn_cast<DenseIntOrFPElementsAttr>(attr)) {
2300 if (printerFlags.shouldElideElementsAttr(intOrFpEltAttr)) {
2301 printElidedElementsAttr(os);
2304 printDenseIntOrFPElementsAttr(intOrFpEltAttr, /*allowHex=*/true);
2308 } else if (auto strEltAttr = llvm::dyn_cast<DenseStringElementsAttr>(attr)) {
2309 if (printerFlags.shouldElideElementsAttr(strEltAttr)) {
2310 printElidedElementsAttr(os);
2313 printDenseStringElementsAttr(strEltAttr);
2317 } else if (auto sparseEltAttr = llvm::dyn_cast<SparseElementsAttr>(attr)) {
2318 if (printerFlags.shouldElideElementsAttr(sparseEltAttr.getIndices()) ||
2319 printerFlags.shouldElideElementsAttr(sparseEltAttr.getValues())) {
2320 printElidedElementsAttr(os);
2323 DenseIntElementsAttr indices = sparseEltAttr.getIndices();
2324 if (indices.getNumElements() != 0) {
2325 printDenseIntOrFPElementsAttr(indices, /*allowHex=*/false);
2327 printDenseElementsAttr(sparseEltAttr.getValues(), /*allowHex=*/true);
2331 } else if (auto stridedLayoutAttr = llvm::dyn_cast<StridedLayoutAttr>(attr)) {
2332 stridedLayoutAttr.print(os);
2333 } else if (auto denseArrayAttr = llvm::dyn_cast<DenseArrayAttr>(attr)) {
2335 printType(denseArrayAttr.getElementType());
2336 if (!denseArrayAttr.empty()) {
2338 printDenseArrayAttr(denseArrayAttr);
2342 } else if (auto resourceAttr =
2343 llvm::dyn_cast<DenseResourceElementsAttr>(attr)) {
2344 os << "dense_resource<
";
2345 printResourceHandle(resourceAttr.getRawHandle());
2347 } else if (auto locAttr = llvm::dyn_cast<LocationAttr>(attr)) {
2348 printLocation(locAttr);
2350 llvm::report_fatal_error("Unknown builtin attribute
");
2352 // Don't print the type if we must elide it, or if it is a None type.
2353 if (typeElision != AttrTypeElision::Must) {
2354 if (auto typedAttr = llvm::dyn_cast<TypedAttr>(attr)) {
2355 Type attrType = typedAttr.getType();
2356 if (!llvm::isa<NoneType>(attrType)) {
2358 printType(attrType);
2365 static void printDenseIntElement(const APInt &value, raw_ostream &os,
2367 if (type.isInteger(1))
2368 os << (value.getBoolValue() ? "
true" : "false");
2370 value.print(os, !type.isUnsignedInteger());
2374 printDenseElementsAttrImpl(bool isSplat, ShapedType type, raw_ostream &os,
2375 function_ref<void(unsigned)> printEltFn) {
2376 // Special case for 0-d and splat tensors.
2378 return printEltFn(0);
2380 // Special case for degenerate tensors.
2381 auto numElements = type.getNumElements();
2382 if (numElements == 0)
2385 // We use a mixed-radix counter to iterate through the shape. When we bump a
2386 // non-least-significant digit, we emit a close bracket. When we next emit an
2387 // element we re-open all closed brackets.
2389 // The mixed-radix counter, with radices in 'shape'.
2390 int64_t rank = type.getRank();
2391 SmallVector<unsigned, 4> counter(rank, 0);
2392 // The number of brackets that have been opened and not closed.
2393 unsigned openBrackets = 0;
2395 auto shape = type.getShape();
2396 auto bumpCounter = [&] {
2397 // Bump the least significant digit.
2398 ++counter[rank - 1];
2399 // Iterate backwards bubbling back the increment.
2400 for (unsigned i = rank - 1; i > 0; --i)
2401 if (counter[i] >= shape[i]) {
2402 // Index 'i' is rolled over. Bump (i-1) and close a bracket.
2410 for (unsigned idx = 0, e = numElements; idx != e; ++idx) {
2413 while (openBrackets++ < rank)
2415 openBrackets = rank;
2419 while (openBrackets-- > 0)
2423 void AsmPrinter::Impl::printDenseElementsAttr(DenseElementsAttr attr,
2425 if (auto stringAttr = llvm::dyn_cast<DenseStringElementsAttr>(attr))
2426 return printDenseStringElementsAttr(stringAttr);
2428 printDenseIntOrFPElementsAttr(llvm::cast<DenseIntOrFPElementsAttr>(attr),
2432 void AsmPrinter::Impl::printDenseIntOrFPElementsAttr(
2433 DenseIntOrFPElementsAttr attr, bool allowHex) {
2434 auto type = attr.getType();
2435 auto elementType = type.getElementType();
2437 // Check to see if we should format this attribute as a hex string.
2438 auto numElements = type.getNumElements();
2439 if (!attr.isSplat() && allowHex &&
2440 shouldPrintElementsAttrWithHex(numElements)) {
2441 ArrayRef<char> rawData = attr.getRawData();
2442 if (llvm::endianness::native == llvm::endianness::big) {
2443 // Convert endianess in big-endian(BE) machines. `rawData` is BE in BE
2444 // machines. It is converted here to print in LE format.
2445 SmallVector<char, 64> outDataVec(rawData.size());
2446 MutableArrayRef<char> convRawData(outDataVec);
2447 DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
2448 rawData, convRawData, type);
2449 printHexString(convRawData);
2451 printHexString(rawData);
2457 if (ComplexType complexTy = llvm::dyn_cast<ComplexType>(elementType)) {
2458 Type complexElementType = complexTy.getElementType();
2459 // Note: The if and else below had a common lambda function which invoked
2460 // printDenseElementsAttrImpl. This lambda was hitting a bug in gcc 9.1,9.2
2461 // and hence was replaced.
2462 if (llvm::isa<IntegerType>(complexElementType)) {
2463 auto valueIt = attr.value_begin<std::complex<APInt>>();
2464 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2465 auto complexValue = *(valueIt + index);
2467 printDenseIntElement(complexValue.real(), os, complexElementType);
2469 printDenseIntElement(complexValue.imag(), os, complexElementType);
2473 auto valueIt = attr.value_begin<std::complex<APFloat>>();
2474 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2475 auto complexValue = *(valueIt + index);
2477 printFloatValue(complexValue.real(), os);
2479 printFloatValue(complexValue.imag(), os);
2483 } else if (elementType.isIntOrIndex()) {
2484 auto valueIt = attr.value_begin<APInt>();
2485 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2486 printDenseIntElement(*(valueIt + index), os, elementType);
2489 assert(llvm::isa<FloatType>(elementType) && "unexpected element type
");
2490 auto valueIt = attr.value_begin<APFloat>();
2491 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2492 printFloatValue(*(valueIt + index), os);
2497 void AsmPrinter::Impl::printDenseStringElementsAttr(
2498 DenseStringElementsAttr attr) {
2499 ArrayRef<StringRef> data = attr.getRawStringData();
2500 auto printFn = [&](unsigned index) { printEscapedString(data[index]); };
2501 printDenseElementsAttrImpl(attr.isSplat(), attr.getType(), os, printFn);
2504 void AsmPrinter::Impl::printDenseArrayAttr(DenseArrayAttr attr) {
2505 Type type = attr.getElementType();
2506 unsigned bitwidth = type.isInteger(1) ? 8 : type.getIntOrFloatBitWidth();
2507 unsigned byteSize = bitwidth / 8;
2508 ArrayRef<char> data = attr.getRawData();
2510 auto printElementAt = [&](unsigned i) {
2511 APInt value(bitwidth, 0);
2513 llvm::LoadIntFromMemory(
2514 value, reinterpret_cast<const uint8_t *>(data.begin() + byteSize * i),
2517 // Print the data as-is or as a float.
2518 if (type.isIntOrIndex()) {
2519 printDenseIntElement(value, getStream(), type);
2521 APFloat fltVal(llvm::cast<FloatType>(type).getFloatSemantics(), value);
2522 printFloatValue(fltVal, getStream());
2525 llvm::interleaveComma(llvm::seq<unsigned>(0, attr.size()), getStream(),
2529 void AsmPrinter::Impl::printType(Type type) {
2531 os << "<<NULL TYPE>>
";
2535 // Try to print an alias for this type.
2536 if (succeeded(printAlias(type)))
2538 return printTypeImpl(type);
2541 void AsmPrinter::Impl::printTypeImpl(Type type) {
2542 TypeSwitch<Type>(type)
2543 .Case<OpaqueType>([&](OpaqueType opaqueTy) {
2544 printDialectSymbol(os, "!
", opaqueTy.getDialectNamespace(),
2545 opaqueTy.getTypeData());
2547 .Case<IndexType>([&](Type) { os << "index
"; })
2548 .Case<Float8E5M2Type>([&](Type) { os << "f8E5M2
"; })
2549 .Case<Float8E4M3FNType>([&](Type) { os << "f8E4M3FN
"; })
2550 .Case<Float8E5M2FNUZType>([&](Type) { os << "f8E5M2FNUZ
"; })
2551 .Case<Float8E4M3FNUZType>([&](Type) { os << "f8E4M3FNUZ
"; })
2552 .Case<Float8E4M3B11FNUZType>([&](Type) { os << "f8E4M3B11FNUZ
"; })
2553 .Case<BFloat16Type>([&](Type) { os << "bf16"; })
2554 .Case<Float16Type>([&](Type) { os << "f16"; })
2555 .Case<FloatTF32Type>([&](Type) { os << "tf32
"; })
2556 .Case<Float32Type>([&](Type) { os << "f32
"; })
2557 .Case<Float64Type>([&](Type) { os << "f64
"; })
2558 .Case<Float80Type>([&](Type) { os << "f80
"; })
2559 .Case<Float128Type>([&](Type) { os << "f128
"; })
2560 .Case<IntegerType>([&](IntegerType integerTy) {
2561 if (integerTy.isSigned())
2563 else if (integerTy.isUnsigned())
2565 os << 'i' << integerTy.getWidth();
2567 .Case<FunctionType>([&](FunctionType funcTy) {
2569 interleaveComma(funcTy.getInputs(), [&](Type ty) { printType(ty); });
2571 ArrayRef<Type> results = funcTy.getResults();
2572 if (results.size() == 1 && !llvm::isa<FunctionType>(results[0])) {
2573 printType(results[0]);
2576 interleaveComma(results, [&](Type ty) { printType(ty); });
2580 .Case<VectorType>([&](VectorType vectorTy) {
2581 auto scalableDims = vectorTy.getScalableDims();
2583 auto vShape = vectorTy.getShape();
2584 unsigned lastDim = vShape.size();
2585 unsigned dimIdx = 0;
2586 for (dimIdx = 0; dimIdx < lastDim; dimIdx++) {
2587 if (!scalableDims.empty() && scalableDims[dimIdx])
2589 os << vShape[dimIdx];
2590 if (!scalableDims.empty() && scalableDims[dimIdx])
2594 printType(vectorTy.getElementType());
2597 .Case<RankedTensorType>([&](RankedTensorType tensorTy) {
2599 printDimensionList(tensorTy.getShape());
2600 if (!tensorTy.getShape().empty())
2602 printType(tensorTy.getElementType());
2603 // Only print the encoding attribute value if set.
2604 if (tensorTy.getEncoding()) {
2606 printAttribute(tensorTy.getEncoding());
2610 .Case<UnrankedTensorType>([&](UnrankedTensorType tensorTy) {
2612 printType(tensorTy.getElementType());
2615 .Case<MemRefType>([&](MemRefType memrefTy) {
2617 printDimensionList(memrefTy.getShape());
2618 if (!memrefTy.getShape().empty())
2620 printType(memrefTy.getElementType());
2621 MemRefLayoutAttrInterface layout = memrefTy.getLayout();
2622 if (!llvm::isa<AffineMapAttr>(layout) || !layout.isIdentity()) {
2624 printAttribute(memrefTy.getLayout(), AttrTypeElision::May);
2626 // Only print the memory space if it is the non-default one.
2627 if (memrefTy.getMemorySpace()) {
2629 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2633 .Case<UnrankedMemRefType>([&](UnrankedMemRefType memrefTy) {
2635 printType(memrefTy.getElementType());
2636 // Only print the memory space if it is the non-default one.
2637 if (memrefTy.getMemorySpace()) {
2639 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2643 .Case<ComplexType>([&](ComplexType complexTy) {
2645 printType(complexTy.getElementType());
2648 .Case<TupleType>([&](TupleType tupleTy) {
2650 interleaveComma(tupleTy.getTypes(),
2651 [&](Type type) { printType(type); });
2654 .Case<NoneType>([&](Type) { os << "none
"; })
2655 .Default([&](Type type) { return printDialectType(type); });
2658 void AsmPrinter::Impl::printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
2659 ArrayRef<StringRef> elidedAttrs,
2661 // If there are no attributes, then there is nothing to be done.
2665 // Functor used to print a filtered attribute list.
2666 auto printFilteredAttributesFn = [&](auto filteredAttrs) {
2667 // Print the 'attributes' keyword if necessary.
2669 os << " attributes
";
2671 // Otherwise, print them all out in braces.
2673 interleaveComma(filteredAttrs,
2674 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2678 // If no attributes are elided, we can directly print with no filtering.
2679 if (elidedAttrs.empty())
2680 return printFilteredAttributesFn(attrs);
2682 // Otherwise, filter out any attributes that shouldn't be included.
2683 llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
2685 auto filteredAttrs = llvm::make_filter_range(attrs, [&](NamedAttribute attr) {
2686 return !elidedAttrsSet.contains(attr.getName().strref());
2688 if (!filteredAttrs.empty())
2689 printFilteredAttributesFn(filteredAttrs);
2691 void AsmPrinter::Impl::printNamedAttribute(NamedAttribute attr) {
2692 // Print the name without quotes if possible.
2693 ::printKeywordOrString(attr.getName().strref(), os);
2695 // Pretty printing elides the attribute value for unit attributes.
2696 if (llvm::isa<UnitAttr>(attr.getValue()))
2700 printAttribute(attr.getValue());
2703 void AsmPrinter::Impl::printDialectAttribute(Attribute attr) {
2704 auto &dialect = attr.getDialect();
2706 // Ask the dialect to serialize the attribute to a string.
2707 std::string attrName;
2709 llvm::raw_string_ostream attrNameStr(attrName);
2710 Impl subPrinter(attrNameStr, state);
2711 DialectAsmPrinter printer(subPrinter);
2712 dialect.printAttribute(attr, printer);
2714 printDialectSymbol(os, "#
", dialect.getNamespace(), attrName);
2717 void AsmPrinter::Impl::printDialectType(Type type) {
2718 auto &dialect = type.getDialect();
2720 // Ask the dialect to serialize the type to a string.
2721 std::string typeName;
2723 llvm::raw_string_ostream typeNameStr(typeName);
2724 Impl subPrinter(typeNameStr, state);
2725 DialectAsmPrinter printer(subPrinter);
2726 dialect.printType(type, printer);
2728 printDialectSymbol(os, "!
", dialect.getNamespace(), typeName);
2731 void AsmPrinter::Impl::printEscapedString(StringRef str) {
2733 llvm::printEscapedString(str, os);
2738 os <<
"\"0x" << llvm::toHex(str) <<
"\"";
2741 printHexString(StringRef(data.data(), data.size()));
2745 return state.pushCyclicPrinting(opaquePointer);
2761 assert(
impl &&
"expected AsmPrinter::getStream to be overriden");
2762 return impl->getStream();
2767 assert(
impl &&
"expected AsmPrinter::printFloat to be overriden");
2772 assert(
impl &&
"expected AsmPrinter::printType to be overriden");
2773 impl->printType(type);
2777 assert(
impl &&
"expected AsmPrinter::printAttribute to be overriden");
2778 impl->printAttribute(attr);
2782 assert(
impl &&
"expected AsmPrinter::printAlias to be overriden");
2783 return impl->printAlias(attr);
2787 assert(
impl &&
"expected AsmPrinter::printAlias to be overriden");
2788 return impl->printAlias(type);
2793 "expected AsmPrinter::printAttributeWithoutType to be overriden");
2798 assert(
impl &&
"expected AsmPrinter::printKeywordOrString to be overriden");
2803 assert(
impl &&
"expected AsmPrinter::printString to be overriden");
2805 printEscapedString(keyword,
getStream());
2810 assert(
impl &&
"expected AsmPrinter::printSymbolName to be overriden");
2815 assert(
impl &&
"expected AsmPrinter::printResourceHandle to be overriden");
2816 impl->printResourceHandle(resource);
2824 return impl->pushCyclicPrinting(opaquePointer);
2835 printAffineExprInternal(expr, BindingStrength::Weak, printValueName);
2841 const char *binopSpelling =
nullptr;
2844 unsigned pos = cast<AffineSymbolExpr>(expr).getPosition();
2846 printValueName(pos,
true);
2852 unsigned pos = cast<AffineDimExpr>(expr).getPosition();
2854 printValueName(pos,
false);
2860 os << cast<AffineConstantExpr>(expr).getValue();
2863 binopSpelling =
" + ";
2866 binopSpelling =
" * ";
2869 binopSpelling =
" floordiv ";
2872 binopSpelling =
" ceildiv ";
2875 binopSpelling =
" mod ";
2879 auto binOp = cast<AffineBinaryOpExpr>(expr);
2885 if (enclosingTightness == BindingStrength::Strong)
2889 auto rhsConst = dyn_cast<AffineConstantExpr>(rhsExpr);
2891 rhsConst.getValue() == -1) {
2893 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
2894 if (enclosingTightness == BindingStrength::Strong)
2899 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
2901 os << binopSpelling;
2902 printAffineExprInternal(rhsExpr, BindingStrength::Strong, printValueName);
2904 if (enclosingTightness == BindingStrength::Strong)
2910 if (enclosingTightness == BindingStrength::Strong)
2915 if (
auto rhs = dyn_cast<AffineBinaryOpExpr>(rhsExpr)) {
2918 if (
auto rrhs = dyn_cast<AffineConstantExpr>(rrhsExpr)) {
2919 if (rrhs.getValue() == -1) {
2920 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
2924 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
2927 printAffineExprInternal(rhs.getLHS(), BindingStrength::Weak,
2931 if (enclosingTightness == BindingStrength::Strong)
2936 if (rrhs.getValue() < -1) {
2937 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
2940 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
2942 os <<
" * " << -rrhs.getValue();
2943 if (enclosingTightness == BindingStrength::Strong)
2952 if (
auto rhsConst = dyn_cast<AffineConstantExpr>(rhsExpr)) {
2953 if (rhsConst.getValue() < 0) {
2954 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
2955 os <<
" - " << -rhsConst.getValue();
2956 if (enclosingTightness == BindingStrength::Strong)
2962 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
2965 printAffineExprInternal(rhsExpr, BindingStrength::Weak, printValueName);
2967 if (enclosingTightness == BindingStrength::Strong)
2972 printAffineExprInternal(expr, BindingStrength::Weak);
2973 isEq ? os <<
" == 0" : os <<
" >= 0";
2979 for (
int i = 0; i < (int)map.
getNumDims() - 1; ++i)
2980 os <<
'd' << i <<
", ";
2989 os <<
's' << i <<
", ";
2998 [&](
AffineExpr expr) { printAffineExpr(expr); });
3005 for (
unsigned i = 1; i < set.
getNumDims(); ++i)
3006 os <<
'd' << i - 1 <<
", ";
3015 os <<
's' << i <<
", ";
3024 for (
int i = 1; i < numConstraints; ++i) {
3028 if (numConstraints >= 1)
3029 printAffineConstraint(set.
getConstraint(numConstraints - 1),
3030 set.
isEq(numConstraints - 1));
3045 explicit OperationPrinter(raw_ostream &os,
AsmStateImpl &state)
3049 void printTopLevelOperation(
Operation *op);
3053 void printFullOpWithIndentAndLoc(
Operation *op);
3059 void printCustomOrGenericOp(
Operation *op)
override;
3061 void printGenericOp(
Operation *op,
bool printOpName)
override;
3064 void printBlockName(
Block *block);
3069 void print(
Block *block,
bool printBlockArgs =
true,
3070 bool printBlockTerminator =
true);
3073 void printValueID(
Value value,
bool printResultNo =
true,
3074 raw_ostream *streamOverride =
nullptr)
const;
3078 raw_ostream *streamOverride =
nullptr)
const;
3086 void printOptionalLocationSpecifier(
Location loc)
override {
3087 printTrailingLocation(loc);
3094 os.indent(currentIndent);
3098 void increaseIndent()
override { currentIndent += indentWidth; }
3101 void decreaseIndent()
override { currentIndent -= indentWidth; }
3110 bool omitType =
false)
override;
3113 void printOperand(
Value value)
override { printValueID(value); }
3114 void printOperand(
Value value, raw_ostream &os)
override {
3115 printValueID(value,
true, &os);
3123 void printOptionalAttrDictWithKeyword(
3131 void printSuccessor(
Block *successor)
override;
3135 void printSuccessorAndUseList(
Block *successor,
3140 bool printBlockTerminators,
bool printEmptyBlock)
override;
3147 state.getSSANameState().shadowRegionArgs(region, namesToUse);
3152 void printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3167 void printValueUsers(
Value value);
3171 void printUserIDs(
Operation *user,
bool prefixComma =
false);
3179 using PrintFn =
function_ref<void(StringRef, ValueFn)>;
3181 ResourceBuilder(PrintFn printFn) : printFn(printFn) {}
3182 ~ResourceBuilder()
override =
default;
3184 void buildBool(StringRef key,
bool data)
final {
3185 printFn(key, [&](raw_ostream &os) { os << (data ?
"true" :
"false"); });
3188 void buildString(StringRef key, StringRef data)
final {
3189 printFn(key, [&](raw_ostream &os) {
3191 llvm::printEscapedString(data, os);
3197 uint32_t dataAlignment)
final {
3198 printFn(key, [&](raw_ostream &os) {
3200 llvm::support::ulittle32_t dataAlignmentLE(dataAlignment);
3202 << llvm::toHex(StringRef(
reinterpret_cast<char *
>(&dataAlignmentLE),
3203 sizeof(dataAlignment)))
3204 << llvm::toHex(StringRef(data.data(), data.size())) <<
"\"";
3213 void printFileMetadataDictionary(
Operation *op);
3219 void printResourceFileMetadata(
function_ref<
void()> checkAddMetadataDict,
3230 const static unsigned indentWidth = 2;
3233 unsigned currentIndent = 0;
3237 void OperationPrinter::printTopLevelOperation(
Operation *op) {
3239 state.getAliasState().printNonDeferredAliases(*
this, newLine);
3242 printFullOpWithIndentAndLoc(op);
3246 state.getAliasState().printDeferredAliases(*
this, newLine);
3249 printFileMetadataDictionary(op);
3252 void OperationPrinter::printFileMetadataDictionary(
Operation *op) {
3253 bool sawMetadataEntry =
false;
3254 auto checkAddMetadataDict = [&] {
3255 if (!std::exchange(sawMetadataEntry,
true))
3256 os << newLine <<
"{-#" << newLine;
3260 printResourceFileMetadata(checkAddMetadataDict, op);
3263 if (sawMetadataEntry)
3264 os << newLine <<
"#-}" << newLine;
3267 void OperationPrinter::printResourceFileMetadata(
3270 bool hadResource =
false;
3271 bool needResourceComma =
false;
3272 bool needEntryComma =
false;
3273 auto processProvider = [&](StringRef dictName, StringRef name,
auto &provider,
3274 auto &&...providerArgs) {
3275 bool hadEntry =
false;
3276 auto printFn = [&](StringRef key, ResourceBuilder::ValueFn valueFn) {
3277 checkAddMetadataDict();
3279 auto printFormatting = [&]() {
3281 if (!std::exchange(hadResource,
true)) {
3282 if (needResourceComma)
3283 os <<
"," << newLine;
3284 os <<
" " << dictName <<
"_resources: {" << newLine;
3287 if (!std::exchange(hadEntry,
true)) {
3289 os <<
"," << newLine;
3290 os <<
" " << name <<
": {" << newLine;
3292 os <<
"," << newLine;
3296 std::optional<uint64_t> charLimit =
3298 if (charLimit.has_value()) {
3299 std::string resourceStr;
3300 llvm::raw_string_ostream ss(resourceStr);
3304 if (resourceStr.size() > charLimit.value())
3308 os <<
" " << key <<
": " << resourceStr;
3311 os <<
" " << key <<
": ";
3315 ResourceBuilder entryBuilder(printFn);
3316 provider.buildResources(op, providerArgs..., entryBuilder);
3318 needEntryComma |= hadEntry;
3320 os << newLine <<
" }";
3326 auto &dialectResources = state.getDialectResources();
3327 StringRef name = interface.getDialect()->getNamespace();
3328 auto it = dialectResources.find(interface.getDialect());
3329 if (it != dialectResources.end())
3330 processProvider(
"dialect", name, interface, it->second);
3332 processProvider(
"dialect", name, interface,
3336 os << newLine <<
" }";
3340 needEntryComma =
false;
3341 needResourceComma = hadResource;
3342 hadResource =
false;
3343 for (
const auto &printer : state.getResourcePrinters())
3344 processProvider(
"external", printer.getName(), printer);
3346 os << newLine <<
" }";
3354 void OperationPrinter::printRegionArgument(
BlockArgument arg,
3362 printOptionalAttrDict(argAttrs);
3364 printTrailingLocation(arg.
getLoc(),
false);
3367 void OperationPrinter::printFullOpWithIndentAndLoc(
Operation *op) {
3369 state.registerOperationLocation(op, newLine.curLine, currentIndent);
3371 os.indent(currentIndent);
3373 printTrailingLocation(op->
getLoc());
3375 printUsersComment(op);
3378 void OperationPrinter::printFullOp(
Operation *op) {
3380 auto printResultGroup = [&](
size_t resultNo,
size_t resultCount) {
3381 printValueID(op->
getResult(resultNo),
false);
3382 if (resultCount > 1)
3383 os <<
':' << resultCount;
3387 ArrayRef<int> resultGroups = state.getSSANameState().getOpResultGroups(op);
3388 if (!resultGroups.empty()) {
3391 interleaveComma(llvm::seq<int>(0, resultGroups.size() - 1), [&](
int i) {
3392 printResultGroup(resultGroups[i],
3393 resultGroups[i + 1] - resultGroups[i]);
3396 printResultGroup(resultGroups.back(), numResults - resultGroups.back());
3399 printResultGroup(0, numResults);
3405 printCustomOrGenericOp(op);
3408 void OperationPrinter::printUsersComment(
Operation *op) {
3412 printOperationID(op);
3413 }
else if (numResults && op->
use_empty()) {
3415 }
else if (numResults && !op->
use_empty()) {
3418 unsigned usedInNResults = 0;
3419 unsigned usedInNOperations = 0;
3422 if (userSet.insert(user).second) {
3423 ++usedInNOperations;
3424 usedInNResults += user->getNumResults();
3429 bool exactlyOneUniqueUse =
3430 usedInNResults <= 1 && usedInNOperations <= 1 && numResults == 1;
3431 os <<
" // " << (exactlyOneUniqueUse ?
"user" :
"users") <<
": ";
3432 bool shouldPrintBrackets = numResults > 1;
3433 auto printOpResult = [&](
OpResult opResult) {
3434 if (shouldPrintBrackets)
3436 printValueUsers(opResult);
3437 if (shouldPrintBrackets)
3441 interleaveComma(op->
getResults(), printOpResult);
3445 void OperationPrinter::printUsersComment(
BlockArgument arg) {
3451 os <<
" is used by ";
3452 printValueUsers(arg);
3457 void OperationPrinter::printValueUsers(
Value value) {
3465 if (userSet.insert(user).second)
3466 printUserIDs(user, index);
3470 void OperationPrinter::printUserIDs(
Operation *user,
bool prefixComma) {
3475 printOperationID(user);
3478 [
this](
Value result) { printValueID(result); });
3482 void OperationPrinter::printCustomOrGenericOp(
Operation *op) {
3488 opInfo->printAssembly(op, *
this, defaultDialectStack.back());
3493 if (
auto opPrinter = dialect->getOperationPrinter(op)) {
3498 if (name.count(
'.') == 1)
3499 name.consume_front((defaultDialectStack.back() +
".").str());
3503 opPrinter(op, *
this);
3510 printGenericOp(op,
true);
3513 void OperationPrinter::printGenericOp(
Operation *op,
bool printOpName) {
3517 interleaveComma(op->
getOperands(), [&](
Value value) { printValueID(value); });
3524 [&](
Block *successor) { printBlockName(successor); });
3536 if (op->getNumRegions() != 0) {
3538 interleaveComma(op->getRegions(), [&](Region ®ion) {
3539 printRegion(region, /*printEntryBlockArgs=*/true,
3540 /*printBlockTerminators=*/true, /*printEmptyBlock=*/true);
3545 printOptionalAttrDict(op->getPropertiesStorage()
3546 ? llvm::to_vector(op->getDiscardableAttrs())
3549 // Print the type signature of the operation.
3551 printFunctionalType(op);
3554 void OperationPrinter::printBlockName(Block *block) {
3555 os << state.getSSANameState().getBlockInfo(block).name;
3558 void OperationPrinter::print(Block *block, bool printBlockArgs,
3559 bool printBlockTerminator) {
3560 // Print the block label and argument list if requested.
3561 if (printBlockArgs) {
3562 os.indent(currentIndent);
3563 printBlockName(block);
3565 // Print the argument list if non-empty.
3566 if (!block->args_empty()) {
3568 interleaveComma(block->getArguments(), [&](BlockArgument arg) {
3571 printType(arg.getType());
3572 // TODO: We should allow location aliases on block arguments.
3573 printTrailingLocation(arg.getLoc(), /*allowAlias*/ false);
3579 // Print out some context information about the predecessors of this block.
3580 if (!block->getParent()) {
3581 os << " // block is not in a region!";
3582 } else if (block->hasNoPredecessors()) {
3583 if (!block->isEntryBlock())
3584 os << " // no predecessors";
3585 } else if (auto *pred = block->getSinglePredecessor()) {
3587 printBlockName(pred);
3589 // We want to print the predecessors in a stable order, not in
3590 // whatever order the use-list is in, so gather and sort them.
3591 SmallVector<BlockInfo, 4> predIDs;
3592 for (auto *pred : block->getPredecessors())
3593 predIDs.push_back(state.getSSANameState().getBlockInfo(pred));
3594 llvm::sort(predIDs, [](BlockInfo lhs, BlockInfo rhs) {
3595 return lhs.ordering < rhs.ordering;
3598 os << " // " << predIDs.size() << " preds: ";
3600 interleaveComma(predIDs, [&](BlockInfo pred) { os << pred.name; });
3605 currentIndent += indentWidth;
3607 if (printerFlags.shouldPrintValueUsers()) {
3608 for (BlockArgument arg : block->getArguments()) {
3609 os.indent(currentIndent);
3610 printUsersComment(arg);
3614 bool hasTerminator =
3615 !block->empty() && block->back().hasTrait<OpTrait::IsTerminator>();
3616 auto range = llvm::make_range(
3618 std::prev(block->end(),
3619 (!hasTerminator || printBlockTerminator) ? 0 : 1));
3620 for (auto &op : range) {
3621 printFullOpWithIndentAndLoc(&op);
3624 currentIndent -= indentWidth;
3627 void OperationPrinter::printValueID(Value value, bool printResultNo,
3628 raw_ostream *streamOverride) const {
3629 state.getSSANameState().printValueID(value, printResultNo,
3630 streamOverride ? *streamOverride : os);
3633 void OperationPrinter::printOperationID(Operation *op,
3634 raw_ostream *streamOverride) const {
3635 state.getSSANameState().printOperationID(op, streamOverride ? *streamOverride
3639 void OperationPrinter::printSuccessor(Block *successor) {
3640 printBlockName(successor);
3643 void OperationPrinter::printSuccessorAndUseList(Block *successor,
3644 ValueRange succOperands) {
3645 printBlockName(successor);
3646 if (succOperands.empty())
3650 interleaveComma(succOperands,
3651 [this](Value operand) { printValueID(operand); });
3653 interleaveComma(succOperands,
3654 [this](Value operand) { printType(operand.getType()); });
3658 void OperationPrinter::printRegion(Region ®ion, bool printEntryBlockArgs,
3659 bool printBlockTerminators,
3660 bool printEmptyBlock) {
3661 if (printerFlags.shouldSkipRegions()) {
3665 os << "{" << newLine;
3666 if (!region.empty()) {
3667 auto restoreDefaultDialect =
3668 llvm::make_scope_exit([&]() { defaultDialectStack.pop_back(); });
3669 if (auto iface = dyn_cast<OpAsmOpInterface>(region.getParentOp()))
3670 defaultDialectStack.push_back(iface.getDefaultDialect());
3672 defaultDialectStack.push_back("");
3674 auto *entryBlock = ®ion.front();
3675 // Force printing the block header if printEmptyBlock is set and the block
3676 // is empty or if printEntryBlockArgs is set and there are arguments to
3678 bool shouldAlwaysPrintBlockHeader =
3679 (printEmptyBlock && entryBlock->empty()) ||
3680 (printEntryBlockArgs && entryBlock->getNumArguments() != 0);
3681 print(entryBlock, shouldAlwaysPrintBlockHeader, printBlockTerminators);
3682 for (auto &b : llvm::drop_begin(region.getBlocks(), 1))
3685 os.indent(currentIndent) << "}";
3688 void OperationPrinter::printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3689 ValueRange operands) {
3691 os << "<<NULL AFFINE MAP>>";
3694 AffineMap map = mapAttr.getValue();
3695 unsigned numDims = map.getNumDims();
3696 auto printValueName = [&](unsigned pos, bool isSymbol) {
3697 unsigned index = isSymbol ? numDims + pos : pos;
3698 assert(index < operands.size());
3701 printValueID(operands[index]);
3706 interleaveComma(map.getResults(), [&](AffineExpr expr) {
3707 printAffineExpr(expr, printValueName);
3711 void OperationPrinter::printAffineExprOfSSAIds(AffineExpr expr,
3712 ValueRange dimOperands,
3713 ValueRange symOperands) {
3714 auto printValueName = [&](unsigned pos, bool isSymbol) {
3716 return printValueID(dimOperands[pos]);
3718 printValueID(symOperands[pos]);
3721 printAffineExpr(expr, printValueName);
3724 //===----------------------------------------------------------------------===//
3725 // print and dump methods
3726 //===----------------------------------------------------------------------===//
3728 void Attribute::print(raw_ostream &os, bool elideType) const {
3730 os << "<<NULL ATTRIBUTE>>";
3734 AsmState state(getContext());
3735 print(os, state, elideType);
3737 void Attribute::print(raw_ostream &os, AsmState &state, bool elideType) const {
3738 using AttrTypeElision = AsmPrinter::Impl::AttrTypeElision;
3739 AsmPrinter::Impl(os, state.getImpl())
3740 .printAttribute(*this, elideType ? AttrTypeElision::Must
3741 : AttrTypeElision::Never);
3744 void Attribute::dump() const {
3745 print(llvm::errs());
3746 llvm::errs() << "\n";
3749 void Attribute::printStripped(raw_ostream &os, AsmState &state) const {
3751 os << "<<NULL ATTRIBUTE>>";
3755 AsmPrinter::Impl subPrinter(os, state.getImpl());
3756 if (succeeded(subPrinter.printAlias(*this)))
3759 auto &dialect = this->getDialect();
3760 uint64_t posPrior = os.tell();
3761 DialectAsmPrinter printer(subPrinter);
3762 dialect.printAttribute(*this, printer);
3763 if (posPrior != os.tell())
3766 // Fallback to printing with prefix if the above failed to write anything
3767 // to the output stream.
3770 void Attribute::printStripped(raw_ostream &os) const {
3772 os << "<<NULL ATTRIBUTE>>";
3776 AsmState state(getContext());
3777 printStripped(os, state);
3780 void Type::print(raw_ostream &os) const {
3782 os << "<<NULL TYPE>>";
3786 AsmState state(getContext());
3789 void Type::print(raw_ostream &os, AsmState &state) const {
3790 AsmPrinter::Impl(os, state.getImpl()).printType(*this);
3793 void Type::dump() const {
3794 print(llvm::errs());
3795 llvm::errs() << "\n";
3798 void AffineMap::dump() const {
3799 print(llvm::errs());
3800 llvm::errs() << "\n";
3803 void IntegerSet::dump() const {
3804 print(llvm::errs());
3805 llvm::errs() << "\n";
3808 void AffineExpr::print(raw_ostream &os) const {
3810 os << "<<NULL AFFINE EXPR>>";
3813 AsmState state(getContext());
3814 AsmPrinter::Impl(os, state.getImpl()).printAffineExpr(*this);
3817 void AffineExpr::dump() const {
3818 print(llvm::errs());
3819 llvm::errs() << "\n";
3822 void AffineMap::print(raw_ostream &os) const {
3824 os << "<<NULL AFFINE MAP>>";
3827 AsmState state(getContext());
3828 AsmPrinter::Impl(os, state.getImpl()).printAffineMap(*this);
3831 void IntegerSet::print(raw_ostream &os) const {
3832 AsmState state(getContext());
3833 AsmPrinter::Impl(os, state.getImpl()).printIntegerSet(*this);
3836 void Value::print(raw_ostream &os) const { print(os, OpPrintingFlags()); }
3837 void Value::print(raw_ostream &os, const OpPrintingFlags &flags) const {
3839 os << "<<NULL VALUE>>";
3843 if (auto *op = getDefiningOp())
3844 return op->print(os, flags);
3845 // TODO: Improve BlockArgument print'ing.
3847 os <<
"<block argument> of type '" << arg.
getType()
3852 os <<
"<<NULL VALUE>>";
3856 if (
auto *op = getDefiningOp())
3857 return op->
print(os, state);
3861 os <<
"<block argument> of type '" << arg.
getType()
3866 print(llvm::errs());
3867 llvm::errs() <<
"\n";
3875 state.getImpl().getSSANameState().printValueID(*
this,
true,
3898 if (
auto result = llvm::dyn_cast<OpResult>(*
this)) {
3901 op = llvm::cast<BlockArgument>(*this).getOwner()->
getParentOp();
3903 os <<
"<<UNKNOWN SSA VALUE>>";
3909 printAsOperand(os, state);
3919 OperationPrinter printer(os, state.getImpl());
3920 if (!getParent() && !state.getPrinterFlags().shouldUseLocalScope()) {
3921 state.getImpl().initializeAliases(
this);
3922 printer.printTopLevelOperation(
this);
3924 printer.printFullOpWithIndentAndLoc(
this);
3930 llvm::errs() <<
"\n";
3936 os <<
"<<UNLINKED BLOCK>>\n";
3947 OperationPrinter(os, state.getImpl()).print(
this);
3956 os <<
"<<UNLINKED BLOCK>>\n";
3960 printAsOperand(os, state);
3963 OperationPrinter printer(os, state.getImpl());
3964 printer.printBlockName(
this);
3974 if (dimensions.empty())
3977 if (dimensions.empty())
3987 <<
"Failed parsing dimension list.";
3998 <<
"Failed parsing dimension list.";
4000 if (shapeArr.empty()) {
4002 <<
"Failed parsing dimension list. Did you mean an empty list? It "
4003 "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 bool shouldPrintElementsAttrWithHex(int64_t numElements)
Returns true if an ElementsAttr with the given number of elements should be printed with hex.
static llvm::ManagedStatic< AsmPrinterOptions > clOptions
static Operation * findParent(Operation *op, bool shouldUseLocalScope)
static void printKeywordOrString(StringRef keyword, raw_ostream &os)
Print the given string as a keyword, or a quoted and escaped string if it has any special or non-prin...
static bool isDialectSymbolSimpleEnoughForPrettyForm(StringRef symName)
Returns true if the given dialect symbol data is simple enough to print in the pretty form.
static void printDialectSymbol(raw_ostream &os, StringRef symPrefix, StringRef dialectName, StringRef symString)
Print the given dialect symbol to the stream.
static OpPrintingFlags verifyOpAndAdjustFlags(Operation *op, OpPrintingFlags printerFlags)
Verifies the operation and switches to generic op printing if verification fails.
static void printFloatValue(const APFloat &apValue, raw_ostream &os)
Print a floating point value in a way that the parser will be able to round-trip losslessly.
MLIR_CRUNNERUTILS_EXPORT void printString(char const *s)
MLIR_CRUNNERUTILS_EXPORT void printNewline()
static void visit(Operation *op, DenseSet< Operation * > &visited)
Visits all the pdl.operand(s), pdl.result(s), and pdl.operation(s) connected to the given operation.
static MLIRContext * getContext(OpFoldResult val)
static std::string diag(const llvm::Value &value)
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
static void printRegion(llvm::raw_ostream &os, Region *region, OpPrintingFlags &flags)
Base type for affine expression.
AffineExprKind getKind() const
Return the classification for this type.
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
unsigned getNumSymbols() const
unsigned getNumDims() const
ArrayRef< AffineExpr > getResults() const
This class represents an opaque handle to a dialect resource entry.
Dialect * getDialect() const
Return the dialect that owns the resource.
This class represents a single parsed resource entry.
virtual FailureOr< AsmResourceBlob > parseAsBlob(BlobAllocatorFn allocator) const =0
Parse the resource entry represented by a binary blob.
virtual InFlightDiagnostic emitError() const =0
Emit an error at the location of this entry.
virtual AsmResourceEntryKind getKind() const =0
Return the kind of this value.
virtual FailureOr< std::string > parseAsString() const =0
Parse the resource entry represented by a human-readable string.
virtual FailureOr< bool > parseAsBool() const =0
Parse the resource entry represented by a boolean.
virtual StringRef getKey() const =0
Return the key of the resource entry.
MLIRContext * getContext() const
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.
This class provides support for representing a failure result, or a valid value of type T.
A fallback map containing external resources not explicitly handled by another parser/printer.
std::vector< std::unique_ptr< AsmResourcePrinter > > getPrinters()
Build a set of resource printers to print the resources within this map.
An integer set representing a conjunction of one or more affine equalities and inequalities.
unsigned getNumDims() const
unsigned getNumConstraints() const
AffineExpr getConstraint(unsigned idx) const
bool isEq(unsigned idx) const
Returns true if the idx^th constraint is an equality, false if it is an inequality.
unsigned getNumSymbols() const
Location objects represent source locations information in MLIR.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
NamedAttribute represents a combination of a name and an Attribute value.
Attribute getValue() const
Return the value of the attribute.
virtual std::string getResourceKey(const AsmDialectResourceHandle &handle) const
Return a key to use for the given resource.
virtual LogicalResult parseResource(AsmParsedResourceEntry &entry) const
Hook for parsing resource entries.
AliasResult
Holds the result of getAlias hook call.
@ FinalAlias
An alias was provided and it should be used (no other hooks will be checked).
@ NoAlias
The object (type or attribute) is not supported by the hook and an alias was not provided.
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
void printFunctionalType(Operation *op)
Print the complete type of an operation in functional form.
Set of flags used to control the behavior of the various IR print methods (e.g.
bool shouldElideElementsAttr(ElementsAttr attr) const
Return if the given ElementsAttr should be elided.
std::optional< int64_t > getLargeElementsAttrLimit() const
Return the size limit for printing large ElementsAttr.
bool shouldAssumeVerified() const
Return if operation verification should be skipped.
OpPrintingFlags & printValueUsers()
Print users of values as comments.
bool shouldUseLocalScope() const
Return if the printer should use local scope when dumping the IR.
bool shouldPrintDebugInfoPrettyForm() const
Return if debug information should be printed in the pretty form.
bool shouldPrintValueUsers() const
Return if the printer should print users of values.
bool shouldPrintGenericOpForm() const
Return if operations should be printed in the generic form.
OpPrintingFlags & elideLargeResourceString(int64_t largeResourceLimit=64)
Enables the elision of large resources strings by omitting them from the dialect_resources section.
bool shouldPrintDebugInfo() const
Return if debug information should be printed.
OpPrintingFlags & elideLargeElementsAttrs(int64_t largeElementLimit=16)
Enables the elision of large elements attributes by printing a lexically valid but otherwise meaningl...
OpPrintingFlags & enableDebugInfo(bool enable=true, bool prettyForm=false)
Enable or disable printing of debug information (based on enable).
OpPrintingFlags()
Initialize the printing flags with default supplied by the cl::opts above.
bool shouldSkipRegions() const
Return if regions should be skipped.
OpPrintingFlags & printGenericOpForm(bool enable=true)
Always print operations in the generic form.
OpPrintingFlags & assumeVerified()
Do not verify the operation when using custom operation printers.
std::optional< uint64_t > getLargeResourceStringLimit() const
Return the size limit in chars for printing large resources.
OpPrintingFlags & useLocalScope()
Use local scope when printing the operation.
OpPrintingFlags & skipRegions(bool skip=true)
Skip printing regions.
This is a value defined by a result of an operation.
Operation * getOwner() const
Returns the operation that owns this result.
unsigned getResultNumber() const
Returns the number of this result.
This class provides the API for ops that are known to be isolated from above.
This class provides the API for ops that are known to be terminators.
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
void printAssembly(Operation *op, OpAsmPrinter &p, StringRef defaultDialect) const
This hook implements the AsmPrinter for this operation.
void print(raw_ostream &os) const
Operation is the basic unit of execution within MLIR.
bool use_empty()
Returns true if this operation has no uses.
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
Dialect * getDialect()
Return the dialect this operation is associated with, or nullptr if the associated dialect is not loa...
unsigned getNumSuccessors()
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
void print(raw_ostream &os, const OpPrintingFlags &flags=std::nullopt)
MLIRContext * getContext()
Return the context this operation is associated with.
std::optional< RegisteredOperationName > getRegisteredInfo()
If this operation has a registered operation description, return it.
Location getLoc()
The source location the operation was defined or derived from.
unsigned getNumOperands()
Attribute getPropertiesAsAttribute()
Return the properties converted to an attribute.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
ArrayRef< NamedAttribute > getAttrs()
Return all of the attributes on this operation.
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
OperationName getName()
The name of an operation is the key identifier for it.
operand_type_range getOperandTypes()
result_type_range getResultTypes()
operand_range getOperands()
Returns an iterator on the underlying Value's.
user_range getUsers()
Returns a range of all users.
SuccessorRange getSuccessors()
result_range getResults()
unsigned getNumResults()
Return the number of results held by this operation.
This class represents success/failure for parsing-like operations that find it important to chain tog...
This class contains a list of basic blocks and a link to the parent operation it is attached to.
iterator_range< OpIterator > getOps()
Operation * getParentOp()
Return the parent operation this region is attached to.
unsigned getNumArguments()
BlockArgument getArgument(unsigned i)
This diagnostic handler is a simple RAII class that registers and erases a diagnostic handler on a gi...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
const void * getAsOpaquePointer() const
Methods for supporting PointerLikeTypeTraits.
Dialect & getDialect() const
Get the dialect this type is registered to.
static Type getFromOpaquePointer(const void *pointer)
bool hasTrait()
Returns true if the type was registered with a particular trait.
void walkImmediateSubElements(function_ref< void(Attribute)> walkAttrsFn, function_ref< void(Type)> walkTypesFn) const
Walk all of the immediately nested sub-attributes and sub-types.
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
bool use_empty() const
Returns true if this value has no uses.
void print(raw_ostream &os) const
Type getType() const
Return the type of this value.
void printAsOperand(raw_ostream &os, AsmState &state) const
Print this value as if it were an operand.
user_range getUsers() const
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
void registerOperationLocation(Operation *op, unsigned line, unsigned col)
Register the location, line and column, within the buffer that the given operation was printed at.
const OpPrintingFlags & getPrinterFlags() const
Get the printer flags.
auto getResourcePrinters()
Return the non-dialect resource printers.
LogicalResult pushCyclicPrinting(const void *opaquePointer)
SSANameState & getSSANameState()
Get the state used for SSA names.
DialectInterfaceCollection< OpAsmDialectInterface > & getDialectInterfaces()
Return the dialects within the context that implement OpAsmDialectInterface.
AliasState & getAliasState()
Get the state used for aliases.
void initializeAliases(Operation *op)
Initialize the alias state to enable the printing of aliases.
AsmStateImpl(Operation *op, const OpPrintingFlags &printerFlags, AsmState::LocationMap *locationMap)
DenseMap< Dialect *, SetVector< AsmDialectResourceHandle > > & getDialectResources()
Return the referenced dialect resources within the printer.
AsmStateImpl(MLIRContext *ctx, const OpPrintingFlags &printerFlags, AsmState::LocationMap *locationMap)
DistinctState & getDistinctState()
Get the state used for distinct attribute identifiers.
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-...
Detect if any of the given parameter types has a sub-element handler.
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.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
ParseResult parseDimensionList(OpAsmParser &parser, DenseI64ArrayAttr &dimensions)
StringRef toString(AsmResourceEntryKind kind)
bool succeeded(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a success value.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
@ CeilDiv
RHS of ceildiv is always a constant or a symbolic expression.
@ Mul
RHS of mul is always a constant or a symbolic expression.
@ Mod
RHS of mod is always a constant or a symbolic expression with a positive value.
@ DimId
Dimensional identifier.
@ FloorDiv
RHS of floordiv is always a constant or a symbolic expression.
@ Constant
Constant integer.
@ SymbolId
Symbolic identifier.
void registerAsmPrinterCLOptions()
Register a set of useful command-line options that can be used to configure various flags within the ...
Type parseType(llvm::StringRef typeStr, MLIRContext *context, size_t *numRead=nullptr, bool isKnownNullTerminated=false)
This parses a single MLIR type to an MLIR context if it was valid.
AsmResourceEntryKind
This enum represents the different kinds of resource values.
@ Blob
A blob of data with an accompanying alignment.
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
raw_ostream & operator<<(raw_ostream &os, const AliasResult &result)
This class represents an efficient way to signal success or failure.
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.