29 #include "llvm/ADT/APFloat.h"
30 #include "llvm/ADT/DenseMap.h"
31 #include "llvm/ADT/MapVector.h"
32 #include "llvm/ADT/STLExtras.h"
33 #include "llvm/ADT/ScopeExit.h"
34 #include "llvm/ADT/ScopedHashTable.h"
35 #include "llvm/ADT/SetVector.h"
36 #include "llvm/ADT/SmallString.h"
37 #include "llvm/ADT/StringExtras.h"
38 #include "llvm/ADT/StringSet.h"
39 #include "llvm/ADT/TypeSwitch.h"
40 #include "llvm/Support/CommandLine.h"
41 #include "llvm/Support/Debug.h"
42 #include "llvm/Support/Endian.h"
43 #include "llvm/Support/Regex.h"
44 #include "llvm/Support/SaveAndRestore.h"
45 #include "llvm/Support/Threading.h"
53 #define DEBUG_TYPE "mlir-asm-printer"
82 auto &os = getStream();
86 *this << (operand ? operand.getType() : Type());
102 *this << (result ? result.getType() : Type());
114 #include "mlir/IR/OpAsmInterface.cpp.inc"
118 return entry.
emitError() <<
"unknown 'resource' key '" << entry.
getKey()
119 <<
"' for dialect '" << getDialect()->getNamespace()
131 struct AsmPrinterOptions {
132 llvm::cl::opt<int64_t> printElementsAttrWithHexIfLarger{
133 "mlir-print-elementsattrs-with-hex-if-larger",
135 "Print DenseElementsAttrs with a hex string that have "
136 "more elements than the given upper limit (use -1 to disable)")};
138 llvm::cl::opt<unsigned> elideElementsAttrIfLarger{
139 "mlir-elide-elementsattrs-if-larger",
140 llvm::cl::desc(
"Elide ElementsAttrs with \"...\" that have "
141 "more elements than the given upper limit")};
143 llvm::cl::opt<bool> printDebugInfoOpt{
144 "mlir-print-debuginfo", llvm::cl::init(
false),
145 llvm::cl::desc(
"Print debug info in MLIR output")};
147 llvm::cl::opt<bool> printPrettyDebugInfoOpt{
148 "mlir-pretty-debuginfo", llvm::cl::init(
false),
149 llvm::cl::desc(
"Print pretty debug info in MLIR output")};
153 llvm::cl::opt<bool> printGenericOpFormOpt{
154 "mlir-print-op-generic", llvm::cl::init(
false),
155 llvm::cl::desc(
"Print the generic op form"), llvm::cl::Hidden};
157 llvm::cl::opt<bool> assumeVerifiedOpt{
158 "mlir-print-assume-verified", llvm::cl::init(
false),
159 llvm::cl::desc(
"Skip op verification when using custom printers"),
162 llvm::cl::opt<bool> printLocalScopeOpt{
163 "mlir-print-local-scope", llvm::cl::init(
false),
164 llvm::cl::desc(
"Print with local scope and inline information (eliding "
165 "aliases for attributes, types, and locations")};
167 llvm::cl::opt<bool> printValueUsers{
168 "mlir-print-value-users", llvm::cl::init(
false),
170 "Print users of operation results and block arguments as a comment")};
174 static llvm::ManagedStatic<AsmPrinterOptions>
clOptions;
185 : printDebugInfoFlag(false), printDebugInfoPrettyFormFlag(false),
186 printGenericOpFormFlag(false), skipRegionsFlag(false),
187 assumeVerifiedFlag(false), printLocalScope(false),
188 printValueUsersFlag(false) {
192 if (
clOptions->elideElementsAttrIfLarger.getNumOccurrences())
193 elementsAttrElementLimit =
clOptions->elideElementsAttrIfLarger;
194 printDebugInfoFlag =
clOptions->printDebugInfoOpt;
195 printDebugInfoPrettyFormFlag =
clOptions->printPrettyDebugInfoOpt;
196 printGenericOpFormFlag =
clOptions->printGenericOpFormOpt;
197 assumeVerifiedFlag =
clOptions->assumeVerifiedOpt;
198 printLocalScope =
clOptions->printLocalScopeOpt;
199 printValueUsersFlag =
clOptions->printValueUsers;
208 elementsAttrElementLimit = largeElementLimit;
216 printDebugInfoFlag = enable;
217 printDebugInfoPrettyFormFlag = prettyForm;
223 printGenericOpFormFlag =
true;
229 skipRegionsFlag =
true;
235 assumeVerifiedFlag =
true;
243 printLocalScope =
true;
249 printValueUsersFlag =
true;
255 return elementsAttrElementLimit &&
256 *elementsAttrElementLimit < int64_t(attr.getNumElements()) &&
262 return elementsAttrElementLimit;
267 return printDebugInfoFlag;
272 return printDebugInfoPrettyFormFlag;
277 return printGenericOpFormFlag;
285 return assumeVerifiedFlag;
293 return printValueUsersFlag;
301 if (
clOptions->printElementsAttrWithHexIfLarger.getNumOccurrences()) {
303 if (
clOptions->printElementsAttrWithHexIfLarger == -1)
305 return numElements >
clOptions->printElementsAttrWithHexIfLarger;
310 return numElements > 100;
321 struct NewLineCounter {
322 unsigned curLine = 1;
325 static raw_ostream &
operator<<(raw_ostream &os, NewLineCounter &newLine) {
344 template <
typename Container,
typename UnaryFunctor>
346 llvm::interleaveComma(c,
os, eachFn);
392 function_ref<
void(
unsigned,
bool)> printValueName =
nullptr);
399 bool withKeyword =
false);
403 bool isTopLevel =
false);
439 function_ref<
void(
unsigned,
bool)> printValueName =
nullptr);
463 SymbolAlias(StringRef name, uint32_t suffixIndex,
bool isType,
465 : name(name), suffixIndex(suffixIndex), isType(isType),
466 isDeferrable(isDeferrable) {}
469 void print(raw_ostream &os)
const {
470 os << (isType ?
"!" :
"#") << name;
476 bool isTypeAlias()
const {
return isType; }
479 bool canBeDeferred()
const {
return isDeferrable; }
485 uint32_t suffixIndex : 30;
489 bool isDeferrable : 1;
495 class AliasInitializer {
499 llvm::BumpPtrAllocator &aliasAllocator)
500 : interfaces(interfaces), aliasAllocator(aliasAllocator),
501 aliasOS(aliasBuffer) {}
504 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias);
512 std::pair<size_t, size_t>
visit(
Attribute attr,
bool canBeDeferred =
false,
513 bool elideType =
false) {
514 return visitImpl(attr, aliases, canBeDeferred, elideType);
521 std::pair<size_t, size_t>
visit(
Type type,
bool canBeDeferred =
false) {
522 return visitImpl(type, aliases, canBeDeferred);
526 struct InProgressAliasInfo {
527 InProgressAliasInfo()
528 : aliasDepth(0), isType(false), canBeDeferred(false) {}
529 InProgressAliasInfo(StringRef alias,
bool isType,
bool canBeDeferred)
530 : alias(alias), aliasDepth(1), isType(isType),
531 canBeDeferred(canBeDeferred) {}
533 bool operator<(
const InProgressAliasInfo &rhs)
const {
535 if (aliasDepth != rhs.aliasDepth)
536 return aliasDepth < rhs.aliasDepth;
537 if (isType != rhs.isType)
539 return alias < rhs.alias;
544 std::optional<StringRef> alias;
547 unsigned aliasDepth : 30;
551 bool canBeDeferred : 1;
561 template <
typename T,
typename... PrintArgs>
562 std::pair<size_t, size_t>
564 llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
565 bool canBeDeferred, PrintArgs &&...printArgs);
568 void markAliasNonDeferrable(
size_t aliasIndex);
572 template <
typename T>
573 void generateAlias(T symbol, InProgressAliasInfo &alias,
bool canBeDeferred);
577 static void initializeAliases(
578 llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
579 llvm::MapVector<const void *, SymbolAlias> &symbolToAlias);
585 llvm::BumpPtrAllocator &aliasAllocator;
588 llvm::MapVector<const void *, InProgressAliasInfo> aliases;
592 llvm::raw_svector_ostream aliasOS;
600 class DummyAliasOperationPrinter :
private OpAsmPrinter {
602 explicit DummyAliasOperationPrinter(
const OpPrintingFlags &printerFlags,
603 AliasInitializer &initializer)
604 : printerFlags(printerFlags), initializer(initializer) {}
608 void printCustomOrGenericOp(
Operation *op)
override {
610 if (printerFlags.shouldPrintDebugInfo())
611 initializer.visit(op->
getLoc(),
true);
614 if (!printerFlags.shouldPrintGenericOpForm()) {
625 void printGenericOp(
Operation *op,
bool printOpName =
true)
override {
627 if (!printerFlags.shouldSkipRegions()) {
641 printAttribute(attr.getValue());
647 void print(
Block *block,
bool printBlockArgs =
true,
648 bool printBlockTerminator =
true) {
651 if (printBlockArgs) {
656 if (printerFlags.shouldPrintDebugInfo())
658 initializer.visit(arg.getLoc(),
false);
666 auto range = llvm::make_range(
668 std::prev(block->
end(),
669 (!hasTerminator || printBlockTerminator) ? 0 : 1));
671 printCustomOrGenericOp(&op);
676 bool printBlockTerminators,
677 bool printEmptyBlock =
false)
override {
680 if (printerFlags.shouldSkipRegions()) {
685 auto *entryBlock = ®ion.
front();
686 print(entryBlock, printEntryBlockArgs, printBlockTerminators);
687 for (
Block &b : llvm::drop_begin(region, 1))
692 bool omitType)
override {
695 if (printerFlags.shouldPrintDebugInfo())
697 initializer.visit(arg.
getLoc(),
false);
701 void printType(
Type type)
override { initializer.visit(type); }
704 void printAttribute(
Attribute attr)
override { initializer.visit(attr); }
705 void printAttributeWithoutType(
Attribute attr)
override {
706 printAttribute(attr);
709 initializer.visit(attr);
713 initializer.visit(type);
718 void printOptionalLocationSpecifier(
Location loc)
override {
728 if (elidedAttrs.empty()) {
730 printAttribute(attr.getValue());
733 llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
736 if (!elidedAttrsSet.contains(attr.getName().strref()))
737 printAttribute(attr.getValue());
739 void printOptionalAttrDictWithKeyword(
742 printOptionalAttrDict(attrs, elidedAttrs);
747 raw_ostream &getStream()
const override {
return os; }
751 void printFloat(
const APFloat &)
override {}
752 void printAffineMapOfSSAIds(AffineMapAttr,
ValueRange)
override {}
755 void increaseIndent()
override {}
756 void decreaseIndent()
override {}
757 void printOperand(
Value)
override {}
758 void printOperand(
Value, raw_ostream &os)
override {
766 void printSymbolName(StringRef)
override {}
767 void printSuccessor(
Block *)
override {}
775 AliasInitializer &initializer;
778 mutable llvm::raw_null_ostream os;
783 explicit DummyAliasDialectAsmPrinter(AliasInitializer &initializer,
786 : initializer(initializer), canBeDeferred(canBeDeferred),
787 childIndices(childIndices) {}
792 template <
typename T,
typename... PrintArgs>
793 size_t printAndVisitNestedAliases(T value, PrintArgs &&...printArgs) {
794 printAndVisitNestedAliasesImpl(value, printArgs...);
795 return maxAliasDepth;
801 void printAndVisitNestedAliasesImpl(
Attribute attr,
bool elideType) {
802 if (!isa<BuiltinDialect>(attr.
getDialect())) {
806 }
else if (attr.
isa<AffineMapAttr, DenseArrayAttr, FloatAttr, IntegerAttr,
807 IntegerSetAttr, UnitAttr>()) {
809 }
else if (
auto dictAttr = dyn_cast<DictionaryAttr>(attr)) {
811 printAttribute(nestedAttr.getName());
812 printAttribute(nestedAttr.getValue());
814 }
else if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr)) {
815 for (
Attribute nestedAttr : arrayAttr.getValue())
816 printAttribute(nestedAttr);
817 }
else if (
auto typeAttr = dyn_cast<TypeAttr>(attr)) {
819 }
else if (
auto locAttr = dyn_cast<OpaqueLoc>(attr)) {
820 printAttribute(locAttr.getFallbackLocation());
821 }
else if (
auto locAttr = dyn_cast<NameLoc>(attr)) {
822 if (!isa<UnknownLoc>(locAttr.getChildLoc()))
823 printAttribute(locAttr.getChildLoc());
824 }
else if (
auto locAttr = dyn_cast<CallSiteLoc>(attr)) {
825 printAttribute(locAttr.getCallee());
826 printAttribute(locAttr.getCaller());
827 }
else if (
auto locAttr = dyn_cast<FusedLoc>(attr)) {
828 if (
Attribute metadata = locAttr.getMetadata())
829 printAttribute(metadata);
830 for (
Location nestedLoc : locAttr.getLocations())
831 printAttribute(nestedLoc);
836 if (
auto typedAttr = attr.
dyn_cast<TypedAttr>()) {
837 Type attrType = typedAttr.getType();
838 if (!attrType.
isa<NoneType>())
843 void printAndVisitNestedAliasesImpl(
Type type) {
848 if (
auto memrefTy = type.
dyn_cast<MemRefType>()) {
850 MemRefLayoutAttrInterface layout = memrefTy.getLayout();
851 if (!layout.isa<AffineMapAttr>() || !layout.isIdentity())
852 printAttribute(memrefTy.getLayout());
853 if (memrefTy.getMemorySpace())
854 printAttribute(memrefTy.getMemorySpace());
859 auto visitFn = [&](
auto element) {
861 (void)printAlias(element);
868 recordAliasResult(initializer.visit(type, canBeDeferred));
872 void printAttribute(
Attribute attr)
override {
873 recordAliasResult(initializer.visit(attr, canBeDeferred));
875 void printAttributeWithoutType(
Attribute attr)
override {
877 initializer.visit(attr, canBeDeferred,
true));
880 printAttribute(attr);
889 void recordAliasResult(std::pair<size_t, size_t> aliasDepthAndIndex) {
890 childIndices.push_back(aliasDepthAndIndex.second);
891 if (aliasDepthAndIndex.first > maxAliasDepth)
892 maxAliasDepth = aliasDepthAndIndex.first;
897 raw_ostream &getStream()
const override {
return os; }
901 void printFloat(
const APFloat &)
override {}
903 void printSymbolName(StringRef)
override {}
907 AliasInitializer &initializer;
916 size_t maxAliasDepth = 0;
919 mutable llvm::raw_null_ostream os;
927 StringRef allowedPunctChars =
"$._-",
928 bool allowTrailingDigit =
true) {
929 assert(!name.empty() &&
"Shouldn't have an empty name here");
931 auto copyNameToBuffer = [&] {
932 for (
char ch : name) {
933 if (llvm::isAlnum(ch) || allowedPunctChars.contains(ch))
934 buffer.push_back(ch);
936 buffer.push_back(
'_');
938 buffer.append(llvm::utohexstr((
unsigned char)ch));
945 if (isdigit(name[0])) {
946 buffer.push_back(
'_');
953 if (!allowTrailingDigit && isdigit(name.back())) {
955 buffer.push_back(
'_');
960 for (
char ch : name) {
961 if (!llvm::isAlnum(ch) && !allowedPunctChars.contains(ch)) {
973 void AliasInitializer::initializeAliases(
974 llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
975 llvm::MapVector<const void *, SymbolAlias> &symbolToAlias) {
976 std::vector<std::pair<const void *, InProgressAliasInfo>> unprocessedAliases =
977 visitedSymbols.takeVector();
978 llvm::stable_sort(unprocessedAliases, [](
const auto &lhs,
const auto &rhs) {
979 return lhs.second < rhs.second;
982 llvm::StringMap<unsigned> nameCounts;
983 for (
auto &[symbol, aliasInfo] : unprocessedAliases) {
984 if (!aliasInfo.alias)
986 StringRef alias = *aliasInfo.alias;
987 unsigned nameIndex = nameCounts[alias]++;
988 symbolToAlias.insert(
989 {symbol, SymbolAlias(alias, nameIndex, aliasInfo.isType,
990 aliasInfo.canBeDeferred)});
994 void AliasInitializer::initialize(
996 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias) {
1000 DummyAliasOperationPrinter aliasPrinter(printerFlags, *
this);
1001 aliasPrinter.printCustomOrGenericOp(op);
1004 initializeAliases(aliases, attrTypeToAlias);
1007 template <
typename T,
typename... PrintArgs>
1008 std::pair<size_t, size_t> AliasInitializer::visitImpl(
1009 T value, llvm::MapVector<const void *, InProgressAliasInfo> &aliases,
1010 bool canBeDeferred, PrintArgs &&...printArgs) {
1011 auto [it, inserted] =
1012 aliases.insert({value.getAsOpaquePointer(), InProgressAliasInfo()});
1013 size_t aliasIndex = std::distance(aliases.begin(), it);
1017 markAliasNonDeferrable(aliasIndex);
1018 return {
static_cast<size_t>(it->second.aliasDepth), aliasIndex};
1022 generateAlias(value, it->second, canBeDeferred);
1026 DummyAliasDialectAsmPrinter printer(*
this, canBeDeferred, childAliases);
1027 size_t maxAliasDepth =
1028 printer.printAndVisitNestedAliases(value, printArgs...);
1031 it = std::next(aliases.begin(), aliasIndex);
1034 it->second.childIndices = std::move(childAliases);
1036 it->second.aliasDepth = maxAliasDepth + 1;
1039 return {(size_t)it->second.aliasDepth, aliasIndex};
1042 void AliasInitializer::markAliasNonDeferrable(
size_t aliasIndex) {
1043 auto it = std::next(aliases.begin(), aliasIndex);
1044 it->second.canBeDeferred =
false;
1047 for (
size_t childIndex : it->second.childIndices)
1048 markAliasNonDeferrable(childIndex);
1051 template <
typename T>
1052 void AliasInitializer::generateAlias(T symbol, InProgressAliasInfo &alias,
1053 bool canBeDeferred) {
1055 for (
const auto &interface : interfaces) {
1057 interface.getAlias(symbol, aliasOS);
1060 nameBuffer = std::move(aliasBuffer);
1061 assert(!nameBuffer.empty() &&
"expected valid alias name");
1066 if (nameBuffer.empty())
1073 name = name.copy(aliasAllocator);
1074 alias = InProgressAliasInfo(name, std::is_base_of_v<Type, T>,
1101 void printNonDeferredAliases(
AsmPrinter::Impl &p, NewLineCounter &newLine) {
1102 printAliases(p, newLine,
false);
1107 printAliases(p, newLine,
true);
1117 llvm::MapVector<const void *, SymbolAlias> attrTypeToAlias;
1120 llvm::BumpPtrAllocator aliasAllocator;
1124 void AliasState::initialize(
1127 AliasInitializer initializer(interfaces, aliasAllocator);
1128 initializer.initialize(op, printerFlags, attrTypeToAlias);
1133 if (it == attrTypeToAlias.end())
1135 it->second.print(os);
1141 if (it == attrTypeToAlias.end())
1144 it->second.print(os);
1148 void AliasState::printAliases(
AsmPrinter::Impl &p, NewLineCounter &newLine,
1150 auto filterFn = [=](
const auto &aliasIt) {
1151 return aliasIt.second.canBeDeferred() == isDeferred;
1153 for (
auto &[opaqueSymbol, alias] :
1154 llvm::make_filter_range(attrTypeToAlias, filterFn)) {
1158 if (alias.isTypeAlias()) {
1191 class SSANameState {
1194 enum :
unsigned { NameSentinel = ~0U };
1197 SSANameState() =
default;
1202 void printValueID(
Value value,
bool printResultNo, raw_ostream &stream)
const;
1205 void printOperationID(
Operation *op, raw_ostream &stream)
const;
1212 BlockInfo getBlockInfo(
Block *block);
1221 void numberValuesInRegion(
Region ®ion);
1222 void numberValuesInBlock(
Block &block);
1229 void getResultIDAndNumber(
OpResult result,
Value &lookupValue,
1230 std::optional<int> &lookupResultNo)
const;
1233 void setValueName(
Value value, StringRef name);
1237 StringRef uniqueValueName(StringRef name);
1260 llvm::ScopedHashTable<StringRef, char> usedNames;
1261 llvm::BumpPtrAllocator usedNameAllocator;
1264 unsigned nextValueID = 0;
1266 unsigned nextArgumentID = 0;
1268 unsigned nextConflictID = 0;
1277 : printerFlags(printerFlags) {
1278 llvm::SaveAndRestore valueIDSaver(nextValueID);
1279 llvm::SaveAndRestore argumentIDSaver(nextArgumentID);
1280 llvm::SaveAndRestore conflictIDSaver(nextConflictID);
1285 using UsedNamesScopeTy = llvm::ScopedHashTable<StringRef, char>::ScopeTy;
1286 using NamingContext =
1287 std::tuple<Region *, unsigned, unsigned, unsigned, UsedNamesScopeTy *>;
1290 llvm::BumpPtrAllocator allocator;
1293 auto *topLevelNamesScope =
1294 new (allocator.Allocate<UsedNamesScopeTy>()) UsedNamesScopeTy(usedNames);
1298 nameContext.push_back(std::make_tuple(®ion, nextValueID, nextArgumentID,
1299 nextConflictID, topLevelNamesScope));
1301 numberValuesInOp(*op);
1303 while (!nameContext.empty()) {
1305 UsedNamesScopeTy *parentScope;
1306 std::tie(region, nextValueID, nextArgumentID, nextConflictID, parentScope) =
1307 nameContext.pop_back_val();
1311 while (usedNames.getCurScope() != parentScope) {
1312 usedNames.getCurScope()->~UsedNamesScopeTy();
1313 assert((usedNames.getCurScope() !=
nullptr || parentScope ==
nullptr) &&
1314 "top level parentScope must be a nullptr");
1318 auto *curNamesScope =
new (allocator.Allocate<UsedNamesScopeTy>())
1319 UsedNamesScopeTy(usedNames);
1321 numberValuesInRegion(*region);
1325 nameContext.push_back(std::make_tuple(®ion, nextValueID,
1326 nextArgumentID, nextConflictID,
1331 while (usedNames.getCurScope() !=
nullptr)
1332 usedNames.getCurScope()->~UsedNamesScopeTy();
1335 void SSANameState::printValueID(
Value value,
bool printResultNo,
1336 raw_ostream &stream)
const {
1338 stream <<
"<<NULL VALUE>>";
1342 std::optional<int> resultNo;
1343 auto lookupValue = value;
1347 if (
OpResult result = dyn_cast<OpResult>(value))
1348 getResultIDAndNumber(result, lookupValue, resultNo);
1350 auto it = valueIDs.find(lookupValue);
1351 if (it == valueIDs.end()) {
1352 stream <<
"<<UNKNOWN SSA VALUE>>";
1357 if (it->second != NameSentinel) {
1358 stream << it->second;
1360 auto nameIt = valueNames.find(lookupValue);
1361 assert(nameIt != valueNames.end() &&
"Didn't have a name entry?");
1362 stream << nameIt->second;
1365 if (resultNo && printResultNo)
1366 stream <<
'#' << *resultNo;
1369 void SSANameState::printOperationID(
Operation *op, raw_ostream &stream)
const {
1370 auto it = operationIDs.find(op);
1371 if (it == operationIDs.end()) {
1372 stream <<
"<<UNKNOWN OPERATION>>";
1374 stream <<
'%' << it->second;
1379 auto it = opResultGroups.find(op);
1380 return it == opResultGroups.end() ?
ArrayRef<int>() : it->second;
1383 BlockInfo SSANameState::getBlockInfo(
Block *block) {
1384 auto it = blockNames.find(block);
1385 BlockInfo invalidBlock{-1,
"INVALIDBLOCK"};
1386 return it != blockNames.end() ? it->second : invalidBlock;
1389 void SSANameState::shadowRegionArgs(
Region ®ion,
ValueRange namesToUse) {
1390 assert(!region.
empty() &&
"cannot shadow arguments of an empty region");
1392 "incorrect number of names passed in");
1394 "only KnownIsolatedFromAbove ops can shadow names");
1397 for (
unsigned i = 0, e = namesToUse.size(); i != e; ++i) {
1398 auto nameToUse = namesToUse[i];
1399 if (nameToUse ==
nullptr)
1404 llvm::raw_svector_ostream nameStream(nameStr);
1405 printValueID(nameToUse,
true, nameStream);
1408 assert(valueIDs[nameToReplace] == NameSentinel);
1411 auto name = StringRef(nameStream.str()).drop_front();
1414 valueNames[nameToReplace] = name.copy(usedNameAllocator);
1418 void SSANameState::numberValuesInRegion(
Region ®ion) {
1419 auto setBlockArgNameFn = [&](
Value arg, StringRef name) {
1420 assert(!valueIDs.count(arg) &&
"arg numbered multiple times");
1422 "arg not defined in current region");
1423 setValueName(arg, name);
1428 if (
auto asmInterface = dyn_cast<OpAsmOpInterface>(op))
1429 asmInterface.getAsmBlockArgumentNames(region, setBlockArgNameFn);
1434 unsigned nextBlockID = 0;
1435 for (
auto &block : region) {
1438 auto blockInfoIt = blockNames.insert({&block, {-1,
""}});
1439 if (blockInfoIt.second) {
1443 llvm::raw_string_ostream(name) <<
"^bb" << nextBlockID;
1444 blockInfoIt.first->second.name = StringRef(name).copy(usedNameAllocator);
1446 blockInfoIt.first->second.ordering = nextBlockID++;
1448 numberValuesInBlock(block);
1452 void SSANameState::numberValuesInBlock(
Block &block) {
1457 llvm::raw_svector_ostream specialName(specialNameBuffer);
1459 if (valueIDs.count(arg))
1462 specialNameBuffer.resize(strlen(
"arg"));
1463 specialName << nextArgumentID++;
1465 setValueName(arg, specialName.str());
1469 for (
auto &op : block)
1470 numberValuesInOp(op);
1473 void SSANameState::numberValuesInOp(
Operation &op) {
1476 auto setResultNameFn = [&](
Value result, StringRef name) {
1477 assert(!valueIDs.count(result) &&
"result numbered multiple times");
1478 assert(result.
getDefiningOp() == &op &&
"result not defined by 'op'");
1479 setValueName(result, name);
1483 resultGroups.push_back(resultNo);
1486 auto setBlockNameFn = [&](
Block *block, StringRef name) {
1488 "getAsmBlockArgumentNames callback invoked on a block not directly "
1489 "nested under the current operation");
1490 assert(!blockNames.count(block) &&
"block numbered multiple times");
1493 if (name.data() != tmpBuffer.data()) {
1494 tmpBuffer.append(name);
1495 name = tmpBuffer.str();
1497 name = name.copy(usedNameAllocator);
1498 blockNames[block] = {-1, name};
1502 if (OpAsmOpInterface asmInterface = dyn_cast<OpAsmOpInterface>(&op)) {
1503 asmInterface.getAsmBlockNames(setBlockNameFn);
1504 asmInterface.getAsmResultNames(setResultNameFn);
1509 if (numResults == 0) {
1512 if (operationIDs.try_emplace(&op, nextValueID).second)
1520 if (valueIDs.try_emplace(resultBegin, nextValueID).second)
1524 if (resultGroups.size() != 1) {
1525 llvm::array_pod_sort(resultGroups.begin(), resultGroups.end());
1526 opResultGroups.try_emplace(&op, std::move(resultGroups));
1530 void SSANameState::getResultIDAndNumber(
1532 std::optional<int> &lookupResultNo)
const {
1540 auto resultGroupIt = opResultGroups.find(owner);
1541 if (resultGroupIt == opResultGroups.end()) {
1543 lookupResultNo = resultNo;
1550 const auto *it = llvm::upper_bound(resultGroups, resultNo);
1551 int groupResultNo = 0, groupSize = 0;
1554 if (it == resultGroups.end()) {
1555 groupResultNo = resultGroups.back();
1556 groupSize =
static_cast<int>(owner->
getNumResults()) - resultGroups.back();
1559 groupResultNo = *std::prev(it);
1560 groupSize = *it - groupResultNo;
1565 lookupResultNo = resultNo - groupResultNo;
1566 lookupValue = owner->
getResult(groupResultNo);
1569 void SSANameState::setValueName(
Value value, StringRef name) {
1572 valueIDs[value] = nextValueID++;
1576 valueIDs[value] = NameSentinel;
1577 valueNames[value] = uniqueValueName(name);
1580 StringRef SSANameState::uniqueValueName(StringRef name) {
1585 if (!usedNames.count(name)) {
1586 name = name.copy(usedNameAllocator);
1592 probeName.push_back(
'_');
1594 probeName += llvm::utostr(nextConflictID++);
1595 if (!usedNames.count(probeName)) {
1596 name = probeName.str().copy(usedNameAllocator);
1599 probeName.resize(name.size() + 1);
1603 usedNames.insert(name,
char());
1611 AsmParsedResourceEntry::~AsmParsedResourceEntry() =
default;
1612 AsmResourceBuilder::~AsmResourceBuilder() =
default;
1613 AsmResourceParser::~AsmResourceParser() =
default;
1614 AsmResourcePrinter::~AsmResourcePrinter() =
default;
1618 case AsmResourceEntryKind::Blob:
1620 case AsmResourceEntryKind::Bool:
1622 case AsmResourceEntryKind::String:
1625 llvm_unreachable(
"unknown AsmResourceEntryKind");
1629 std::unique_ptr<ResourceCollection> &collection = keyToResources[key.str()];
1631 collection = std::make_unique<ResourceCollection>(key);
1635 std::vector<std::unique_ptr<AsmResourcePrinter>>
1637 std::vector<std::unique_ptr<AsmResourcePrinter>> printers;
1638 for (
auto &it : keyToResources) {
1639 ResourceCollection *collection = it.second.get();
1641 return collection->buildResources(op, builder);
1643 printers.emplace_back(
1649 LogicalResult FallbackAsmResourceMap::ResourceCollection::parseResource(
1656 resources.emplace_back(entry.
getKey(), std::move(*blob));
1663 resources.emplace_back(entry.
getKey(), *value);
1670 resources.emplace_back(entry.
getKey(), std::move(*str));
1677 void FallbackAsmResourceMap::ResourceCollection::buildResources(
1679 for (
const auto &entry : resources) {
1680 if (
const auto *value = std::get_if<AsmResourceBlob>(&entry.value))
1682 else if (
const auto *value = std::get_if<bool>(&entry.value))
1684 else if (
const auto *value = std::get_if<std::string>(&entry.value))
1687 llvm_unreachable(
"unknown AsmResourceEntryKind");
1701 : interfaces(op->getContext()), nameState(op, printerFlags),
1702 printerFlags(printerFlags), locationMap(locationMap) {}
1705 : interfaces(ctx), printerFlags(printerFlags), locationMap(locationMap) {}
1709 aliasState.initialize(op, printerFlags, interfaces);
1726 return llvm::make_pointee_range(externalResourcePrinters);
1736 (*locationMap)[op] = std::make_pair(line, col);
1742 return dialectResources;
1756 AliasState aliasState;
1759 SSANameState nameState;
1780 return printerFlags;
1782 LLVM_DEBUG(llvm::dbgs() <<
DEBUG_TYPE <<
": Verifying operation: "
1787 auto parentThreadId = llvm::get_threadid();
1789 if (parentThreadId == llvm::get_threadid()) {
1791 diag.print(llvm::dbgs());
1792 llvm::dbgs() <<
"\n";
1799 LLVM_DEBUG(llvm::dbgs()
1801 <<
"' failed to verify and will be printed in generic form\n");
1805 return printerFlags;
1824 return impl->getPrinterFlags();
1828 std::unique_ptr<AsmResourcePrinter> printer) {
1829 impl->externalResourcePrinters.emplace_back(std::move(printer));
1834 return impl->getDialectResources();
1842 : os(os), state(state), printerFlags(state.getPrinterFlags()) {}
1850 printLocation(loc, allowAlias);
1860 .Case<OpaqueLoc>([&](OpaqueLoc loc) {
1861 printLocationInternal(loc.getFallbackLocation(), pretty);
1863 .Case<UnknownLoc>([&](UnknownLoc loc) {
1869 .Case<FileLineColLoc>([&](FileLineColLoc loc) {
1871 os << loc.getFilename().getValue();
1873 printEscapedString(loc.getFilename());
1874 os <<
':' << loc.getLine() <<
':' << loc.getColumn();
1876 .Case<NameLoc>([&](NameLoc loc) {
1877 printEscapedString(loc.getName());
1880 auto childLoc = loc.getChildLoc();
1881 if (!childLoc.isa<UnknownLoc>()) {
1883 printLocationInternal(childLoc, pretty);
1887 .Case<CallSiteLoc>([&](CallSiteLoc loc) {
1892 printLocationInternal(callee, pretty);
1894 if (callee.
isa<NameLoc>()) {
1895 if (caller.
isa<FileLineColLoc>()) {
1898 os << newLine <<
" at ";
1901 os << newLine <<
" at ";
1906 printLocationInternal(caller, pretty);
1910 .Case<FusedLoc>([&](
FusedLoc loc) {
1913 if (
Attribute metadata = loc.getMetadata()) {
1921 [&](Location loc) { printLocationInternal(loc, pretty); },
1922 [&]() { os << ", "; });
1929 static void printFloatValue(const APFloat &apValue, raw_ostream &os) {
1930 // We would like to output the FP constant value in exponential notation,
1931 // but we cannot do this if doing so will lose precision. Check here to
1932 // make sure that we only output it in exponential format if we can parse
1933 // the value back and get the same value.
1934 bool isInf = apValue.isInfinity();
1935 bool isNaN = apValue.isNaN();
1936 if (!isInf && !isNaN) {
1937 SmallString<128> strValue;
1938 apValue.toString(strValue, /*FormatPrecision=*/6, /*FormatMaxPadding=*/0,
1939 /*TruncateZero=*/false);
1941 // Check to make sure that the stringized number is not some string like
1942 // "Inf" or NaN, that atof will accept, but the lexer will not. Check
1943 // that the string matches the "[-+]?[0-9]" regex.
1944 assert(((strValue[0] >= '0
' && strValue[0] <= '9') ||
1945 ((strValue[0] ==
'-' || strValue[0] ==
'+') &&
1946 (strValue[1] >=
'0' && strValue[1] <=
'9'))) &&
1947 "[-+]?[0-9] regex does not match!");
1951 if (APFloat(apValue.getSemantics(), strValue).bitwiseIsEqual(apValue)) {
1959 apValue.toString(strValue);
1962 if (strValue.str().contains(
'.')) {
1971 APInt apInt = apValue.bitcastToAPInt();
1972 apInt.toString(str, 16,
false,
1979 return printLocationInternal(loc,
true,
true);
1982 if (!allowAlias ||
failed(printAlias(loc)))
1983 printLocationInternal(loc,
false,
true);
1999 if (symName.empty() || !isalpha(symName.front()))
2004 symName = symName.drop_while(
2005 [](
char c) {
return llvm::isAlnum(c) || c ==
'.' || c ==
'_'; });
2006 if (symName.empty())
2011 return symName.front() ==
'<' && symName.back() ==
'>';
2016 StringRef dialectName, StringRef symString) {
2017 os << symPrefix << dialectName;
2022 os <<
'.' << symString;
2026 os << '<' << symString << '>
';
2030 static bool isBareIdentifier(StringRef name) {
2031 // By making this unsigned, the value passed in to isalnum will always be
2032 // in the range 0-255. This is important when building with MSVC because
2033 // its implementation will assert. This situation can arise when dealing
2034 // with UTF-8 multibyte characters.
2035 if (name.empty() || (!isalpha(name[0]) && name[0] != '_
'))
2037 return llvm::all_of(name.drop_front(), [](unsigned char c) {
2038 return isalnum(c) || c == '_
' || c == '$
' || c == '.
';
2044 static void printKeywordOrString(StringRef keyword, raw_ostream &os) {
2045 // If it can be represented as a bare identifier, write it directly.
2046 if (isBareIdentifier(keyword)) {
2051 // Otherwise, output the keyword wrapped in quotes with proper escaping.
2053 printEscapedString(keyword, os);
2060 static void printSymbolReference(StringRef symbolRef, raw_ostream &os) {
2061 if (symbolRef.empty()) {
2062 os << "@<<INVALID EMPTY SYMBOL>>
";
2066 printKeywordOrString(symbolRef, os);
2069 // Print out a valid ElementsAttr that is succinct and can represent any
2070 // potential shape/type, for use when eliding a large ElementsAttr.
2072 // We choose to use a dense resource ElementsAttr literal with conspicuous
2073 // content to hopefully alert readers to the fact that this has been elided.
2074 static void printElidedElementsAttr(raw_ostream &os) {
2075 os << R"(dense_resource<__elided__>)
";
2078 LogicalResult AsmPrinter::Impl::printAlias(Attribute attr) {
2079 return state.getAliasState().getAlias(attr, os);
2082 LogicalResult AsmPrinter::Impl::printAlias(Type type) {
2083 return state.getAliasState().getAlias(type, os);
2086 void AsmPrinter::Impl::printAttribute(Attribute attr,
2087 AttrTypeElision typeElision) {
2089 os << "<<NULL ATTRIBUTE>>
";
2093 // Try to print an alias for this attribute.
2094 if (succeeded(printAlias(attr)))
2096 return printAttributeImpl(attr, typeElision);
2099 void AsmPrinter::Impl::printAttributeImpl(Attribute attr,
2100 AttrTypeElision typeElision) {
2101 if (!isa<BuiltinDialect>(attr.getDialect())) {
2102 printDialectAttribute(attr);
2103 } else if (auto opaqueAttr = attr.dyn_cast<OpaqueAttr>()) {
2104 printDialectSymbol(os, "#
", opaqueAttr.getDialectNamespace(),
2105 opaqueAttr.getAttrData());
2106 } else if (attr.isa<UnitAttr>()) {
2109 } else if (auto dictAttr = attr.dyn_cast<DictionaryAttr>()) {
2111 interleaveComma(dictAttr.getValue(),
2112 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2115 } else if (auto intAttr = attr.dyn_cast<IntegerAttr>()) {
2116 Type intType = intAttr.getType();
2117 if (intType.isSignlessInteger(1)) {
2118 os << (intAttr.getValue().getBoolValue() ? "true" : "false");
2120 // Boolean integer attributes always elides the type.
2124 // Only print attributes as unsigned if they are explicitly unsigned or are
2125 // signless 1-bit values. Indexes, signed values, and multi-bit signless
2126 // values print as signed.
2128 intType.isUnsignedInteger() || intType.isSignlessInteger(1);
2129 intAttr.getValue().print(os, !isUnsigned);
2131 // IntegerAttr elides the type if I64.
2132 if (typeElision == AttrTypeElision::May && intType.isSignlessInteger(64))
2135 } else if (auto floatAttr = attr.dyn_cast<FloatAttr>()) {
2136 printFloatValue(floatAttr.getValue(), os);
2138 // FloatAttr elides the type if F64.
2139 if (typeElision == AttrTypeElision::May && floatAttr.getType().isF64())
2142 } else if (auto strAttr = attr.dyn_cast<StringAttr>()) {
2143 printEscapedString(strAttr.getValue());
2145 } else if (auto arrayAttr = attr.dyn_cast<ArrayAttr>()) {
2147 interleaveComma(arrayAttr.getValue(), [&](Attribute attr) {
2148 printAttribute(attr, AttrTypeElision::May);
2152 } else if (auto affineMapAttr = attr.dyn_cast<AffineMapAttr>()) {
2153 os << "affine_map<
";
2154 affineMapAttr.getValue().print(os);
2157 // AffineMap always elides the type.
2160 } else if (auto integerSetAttr = attr.dyn_cast<IntegerSetAttr>()) {
2161 os << "affine_set<
";
2162 integerSetAttr.getValue().print(os);
2165 // IntegerSet always elides the type.
2168 } else if (auto typeAttr = attr.dyn_cast<TypeAttr>()) {
2169 printType(typeAttr.getValue());
2171 } else if (auto refAttr = attr.dyn_cast<SymbolRefAttr>()) {
2172 printSymbolReference(refAttr.getRootReference().getValue(), os);
2173 for (FlatSymbolRefAttr nestedRef : refAttr.getNestedReferences()) {
2175 printSymbolReference(nestedRef.getValue(), os);
2178 } else if (auto intOrFpEltAttr = attr.dyn_cast<DenseIntOrFPElementsAttr>()) {
2179 if (printerFlags.shouldElideElementsAttr(intOrFpEltAttr)) {
2180 printElidedElementsAttr(os);
2183 printDenseIntOrFPElementsAttr(intOrFpEltAttr, /*allowHex=*/true);
2187 } else if (auto strEltAttr = attr.dyn_cast<DenseStringElementsAttr>()) {
2188 if (printerFlags.shouldElideElementsAttr(strEltAttr)) {
2189 printElidedElementsAttr(os);
2192 printDenseStringElementsAttr(strEltAttr);
2196 } else if (auto sparseEltAttr = attr.dyn_cast<SparseElementsAttr>()) {
2197 if (printerFlags.shouldElideElementsAttr(sparseEltAttr.getIndices()) ||
2198 printerFlags.shouldElideElementsAttr(sparseEltAttr.getValues())) {
2199 printElidedElementsAttr(os);
2202 DenseIntElementsAttr indices = sparseEltAttr.getIndices();
2203 if (indices.getNumElements() != 0) {
2204 printDenseIntOrFPElementsAttr(indices, /*allowHex=*/false);
2206 printDenseElementsAttr(sparseEltAttr.getValues(), /*allowHex=*/true);
2210 } else if (auto stridedLayoutAttr = attr.dyn_cast<StridedLayoutAttr>()) {
2211 stridedLayoutAttr.print(os);
2212 } else if (auto denseArrayAttr = attr.dyn_cast<DenseArrayAttr>()) {
2214 printType(denseArrayAttr.getElementType());
2215 if (!denseArrayAttr.empty()) {
2217 printDenseArrayAttr(denseArrayAttr);
2221 } else if (auto resourceAttr = attr.dyn_cast<DenseResourceElementsAttr>()) {
2222 os << "dense_resource<
";
2223 printResourceHandle(resourceAttr.getRawHandle());
2225 } else if (auto locAttr = attr.dyn_cast<LocationAttr>()) {
2226 printLocation(locAttr);
2228 llvm::report_fatal_error("Unknown builtin attribute
");
2230 // Don't print the type if we must elide it, or if it is a None type.
2231 if (typeElision != AttrTypeElision::Must) {
2232 if (auto typedAttr = attr.dyn_cast<TypedAttr>()) {
2233 Type attrType = typedAttr.getType();
2234 if (!attrType.isa<NoneType>()) {
2236 printType(attrType);
2243 static void printDenseIntElement(const APInt &value, raw_ostream &os,
2245 if (type.isInteger(1))
2246 os << (value.getBoolValue() ? "
true" : "false");
2248 value.print(os, !type.isUnsignedInteger());
2252 printDenseElementsAttrImpl(bool isSplat, ShapedType type, raw_ostream &os,
2253 function_ref<void(unsigned)> printEltFn) {
2254 // Special case for 0-d and splat tensors.
2256 return printEltFn(0);
2258 // Special case for degenerate tensors.
2259 auto numElements = type.getNumElements();
2260 if (numElements == 0)
2263 // We use a mixed-radix counter to iterate through the shape. When we bump a
2264 // non-least-significant digit, we emit a close bracket. When we next emit an
2265 // element we re-open all closed brackets.
2267 // The mixed-radix counter, with radices in 'shape'.
2268 int64_t rank = type.getRank();
2269 SmallVector<unsigned, 4> counter(rank, 0);
2270 // The number of brackets that have been opened and not closed.
2271 unsigned openBrackets = 0;
2273 auto shape = type.getShape();
2274 auto bumpCounter = [&] {
2275 // Bump the least significant digit.
2276 ++counter[rank - 1];
2277 // Iterate backwards bubbling back the increment.
2278 for (unsigned i = rank - 1; i > 0; --i)
2279 if (counter[i] >= shape[i]) {
2280 // Index 'i' is rolled over. Bump (i-1) and close a bracket.
2288 for (unsigned idx = 0, e = numElements; idx != e; ++idx) {
2291 while (openBrackets++ < rank)
2293 openBrackets = rank;
2297 while (openBrackets-- > 0)
2301 void AsmPrinter::Impl::printDenseElementsAttr(DenseElementsAttr attr,
2303 if (auto stringAttr = attr.dyn_cast<DenseStringElementsAttr>())
2304 return printDenseStringElementsAttr(stringAttr);
2306 printDenseIntOrFPElementsAttr(attr.cast<DenseIntOrFPElementsAttr>(),
2310 void AsmPrinter::Impl::printDenseIntOrFPElementsAttr(
2311 DenseIntOrFPElementsAttr attr, bool allowHex) {
2312 auto type = attr.getType();
2313 auto elementType = type.getElementType();
2315 // Check to see if we should format this attribute as a hex string.
2316 auto numElements = type.getNumElements();
2317 if (!attr.isSplat() && allowHex &&
2318 shouldPrintElementsAttrWithHex(numElements)) {
2319 ArrayRef<char> rawData = attr.getRawData();
2320 if (llvm::support::endian::system_endianness() ==
2321 llvm::support::endianness::big) {
2322 // Convert endianess in big-endian(BE) machines. `rawData` is BE in BE
2323 // machines. It is converted here to print in LE format.
2324 SmallVector<char, 64> outDataVec(rawData.size());
2325 MutableArrayRef<char> convRawData(outDataVec);
2326 DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
2327 rawData, convRawData, type);
2328 printHexString(convRawData);
2330 printHexString(rawData);
2336 if (ComplexType complexTy = elementType.dyn_cast<ComplexType>()) {
2337 Type complexElementType = complexTy.getElementType();
2338 // Note: The if and else below had a common lambda function which invoked
2339 // printDenseElementsAttrImpl. This lambda was hitting a bug in gcc 9.1,9.2
2340 // and hence was replaced.
2341 if (complexElementType.isa<IntegerType>()) {
2342 auto valueIt = attr.value_begin<std::complex<APInt>>();
2343 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2344 auto complexValue = *(valueIt + index);
2346 printDenseIntElement(complexValue.real(), os, complexElementType);
2348 printDenseIntElement(complexValue.imag(), os, complexElementType);
2352 auto valueIt = attr.value_begin<std::complex<APFloat>>();
2353 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2354 auto complexValue = *(valueIt + index);
2356 printFloatValue(complexValue.real(), os);
2358 printFloatValue(complexValue.imag(), os);
2362 } else if (elementType.isIntOrIndex()) {
2363 auto valueIt = attr.value_begin<APInt>();
2364 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2365 printDenseIntElement(*(valueIt + index), os, elementType);
2368 assert(elementType.isa<FloatType>() && "unexpected element type
");
2369 auto valueIt = attr.value_begin<APFloat>();
2370 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
2371 printFloatValue(*(valueIt + index), os);
2376 void AsmPrinter::Impl::printDenseStringElementsAttr(
2377 DenseStringElementsAttr attr) {
2378 ArrayRef<StringRef> data = attr.getRawStringData();
2379 auto printFn = [&](unsigned index) { printEscapedString(data[index]); };
2380 printDenseElementsAttrImpl(attr.isSplat(), attr.getType(), os, printFn);
2383 void AsmPrinter::Impl::printDenseArrayAttr(DenseArrayAttr attr) {
2384 Type type = attr.getElementType();
2385 unsigned bitwidth = type.isInteger(1) ? 8 : type.getIntOrFloatBitWidth();
2386 unsigned byteSize = bitwidth / 8;
2387 ArrayRef<char> data = attr.getRawData();
2389 auto printElementAt = [&](unsigned i) {
2390 APInt value(bitwidth, 0);
2392 llvm::LoadIntFromMemory(
2393 value, reinterpret_cast<const uint8_t *>(data.begin() + byteSize * i),
2396 // Print the data as-is or as a float.
2397 if (type.isIntOrIndex()) {
2398 printDenseIntElement(value, getStream(), type);
2400 APFloat fltVal(type.cast<FloatType>().getFloatSemantics(), value);
2401 printFloatValue(fltVal, getStream());
2404 llvm::interleaveComma(llvm::seq<unsigned>(0, attr.size()), getStream(),
2408 void AsmPrinter::Impl::printType(Type type) {
2410 os << "<<NULL TYPE>>
";
2414 // Try to print an alias for this type.
2415 if (succeeded(printAlias(type)))
2417 return printTypeImpl(type);
2420 void AsmPrinter::Impl::printTypeImpl(Type type) {
2421 TypeSwitch<Type>(type)
2422 .Case<OpaqueType>([&](OpaqueType opaqueTy) {
2423 printDialectSymbol(os, "!
", opaqueTy.getDialectNamespace(),
2424 opaqueTy.getTypeData());
2426 .Case<IndexType>([&](Type) { os << "index
"; })
2427 .Case<Float8E5M2Type>([&](Type) { os << "f8E5M2
"; })
2428 .Case<Float8E4M3FNType>([&](Type) { os << "f8E4M3FN
"; })
2429 .Case<Float8E5M2FNUZType>([&](Type) { os << "f8E5M2FNUZ
"; })
2430 .Case<Float8E4M3FNUZType>([&](Type) { os << "f8E4M3FNUZ
"; })
2431 .Case<Float8E4M3B11FNUZType>([&](Type) { os << "f8E4M3B11FNUZ
"; })
2432 .Case<BFloat16Type>([&](Type) { os << "bf16"; })
2433 .Case<Float16Type>([&](Type) { os << "f16"; })
2434 .Case<Float32Type>([&](Type) { os << "f32
"; })
2435 .Case<Float64Type>([&](Type) { os << "f64
"; })
2436 .Case<Float80Type>([&](Type) { os << "f80
"; })
2437 .Case<Float128Type>([&](Type) { os << "f128
"; })
2438 .Case<IntegerType>([&](IntegerType integerTy) {
2439 if (integerTy.isSigned())
2441 else if (integerTy.isUnsigned())
2443 os << 'i' << integerTy.getWidth();
2445 .Case<FunctionType>([&](FunctionType funcTy) {
2447 interleaveComma(funcTy.getInputs(), [&](Type ty) { printType(ty); });
2449 ArrayRef<Type> results = funcTy.getResults();
2450 if (results.size() == 1 && !results[0].isa<FunctionType>()) {
2451 printType(results[0]);
2454 interleaveComma(results, [&](Type ty) { printType(ty); });
2458 .Case<VectorType>([&](VectorType vectorTy) {
2460 auto vShape = vectorTy.getShape();
2461 unsigned lastDim = vShape.size();
2462 unsigned lastFixedDim = lastDim - vectorTy.getNumScalableDims();
2463 unsigned dimIdx = 0;
2464 for (dimIdx = 0; dimIdx < lastFixedDim; dimIdx++)
2465 os << vShape[dimIdx] << 'x';
2466 if (vectorTy.isScalable()) {
2468 unsigned secondToLastDim = lastDim - 1;
2469 for (; dimIdx < secondToLastDim; dimIdx++)
2470 os << vShape[dimIdx] << 'x';
2471 os << vShape[dimIdx] << "]x
";
2473 printType(vectorTy.getElementType());
2476 .Case<RankedTensorType>([&](RankedTensorType tensorTy) {
2478 for (int64_t dim : tensorTy.getShape()) {
2479 if (ShapedType::isDynamic(dim))
2485 printType(tensorTy.getElementType());
2486 // Only print the encoding attribute value if set.
2487 if (tensorTy.getEncoding()) {
2489 printAttribute(tensorTy.getEncoding());
2493 .Case<UnrankedTensorType>([&](UnrankedTensorType tensorTy) {
2495 printType(tensorTy.getElementType());
2498 .Case<MemRefType>([&](MemRefType memrefTy) {
2500 for (int64_t dim : memrefTy.getShape()) {
2501 if (ShapedType::isDynamic(dim))
2507 printType(memrefTy.getElementType());
2508 MemRefLayoutAttrInterface layout = memrefTy.getLayout();
2509 if (!layout.isa<AffineMapAttr>() || !layout.isIdentity()) {
2511 printAttribute(memrefTy.getLayout(), AttrTypeElision::May);
2513 // Only print the memory space if it is the non-default one.
2514 if (memrefTy.getMemorySpace()) {
2516 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2520 .Case<UnrankedMemRefType>([&](UnrankedMemRefType memrefTy) {
2522 printType(memrefTy.getElementType());
2523 // Only print the memory space if it is the non-default one.
2524 if (memrefTy.getMemorySpace()) {
2526 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);
2530 .Case<ComplexType>([&](ComplexType complexTy) {
2532 printType(complexTy.getElementType());
2535 .Case<TupleType>([&](TupleType tupleTy) {
2537 interleaveComma(tupleTy.getTypes(),
2538 [&](Type type) { printType(type); });
2541 .Case<NoneType>([&](Type) { os << "none
"; })
2542 .Default([&](Type type) { return printDialectType(type); });
2545 void AsmPrinter::Impl::printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
2546 ArrayRef<StringRef> elidedAttrs,
2548 // If there are no attributes, then there is nothing to be done.
2552 // Functor used to print a filtered attribute list.
2553 auto printFilteredAttributesFn = [&](auto filteredAttrs) {
2554 // Print the 'attributes' keyword if necessary.
2556 os << " attributes
";
2558 // Otherwise, print them all out in braces.
2560 interleaveComma(filteredAttrs,
2561 [&](NamedAttribute attr) { printNamedAttribute(attr); });
2565 // If no attributes are elided, we can directly print with no filtering.
2566 if (elidedAttrs.empty())
2567 return printFilteredAttributesFn(attrs);
2569 // Otherwise, filter out any attributes that shouldn't be included.
2570 llvm::SmallDenseSet<StringRef> elidedAttrsSet(elidedAttrs.begin(),
2572 auto filteredAttrs = llvm::make_filter_range(attrs, [&](NamedAttribute attr) {
2573 return !elidedAttrsSet.contains(attr.getName().strref());
2575 if (!filteredAttrs.empty())
2576 printFilteredAttributesFn(filteredAttrs);
2579 void AsmPrinter::Impl::printNamedAttribute(NamedAttribute attr) {
2580 // Print the name without quotes if possible.
2581 ::printKeywordOrString(attr.getName().strref(), os);
2583 // Pretty printing elides the attribute value for unit attributes.
2584 if (attr.getValue().isa<UnitAttr>())
2588 printAttribute(attr.getValue());
2591 void AsmPrinter::Impl::printDialectAttribute(Attribute attr) {
2592 auto &dialect = attr.getDialect();
2594 // Ask the dialect to serialize the attribute to a string.
2595 std::string attrName;
2597 llvm::raw_string_ostream attrNameStr(attrName);
2598 Impl subPrinter(attrNameStr, state);
2599 DialectAsmPrinter printer(subPrinter);
2600 dialect.printAttribute(attr, printer);
2602 printDialectSymbol(os, "#
", dialect.getNamespace(), attrName);
2605 void AsmPrinter::Impl::printDialectType(Type type) {
2606 auto &dialect = type.getDialect();
2608 // Ask the dialect to serialize the type to a string.
2609 std::string typeName;
2611 llvm::raw_string_ostream typeNameStr(typeName);
2612 Impl subPrinter(typeNameStr, state);
2613 DialectAsmPrinter printer(subPrinter);
2614 dialect.printType(type, printer);
2616 printDialectSymbol(os, "!
", dialect.getNamespace(), typeName);
2619 void AsmPrinter::Impl::printEscapedString(StringRef str) {
2621 llvm::printEscapedString(str, os);
2626 os <<
"\"0x" << llvm::toHex(str) <<
"\"";
2629 printHexString(StringRef(data.data(), data.size()));
2639 assert(
impl &&
"expected AsmPrinter::getStream to be overriden");
2640 return impl->getStream();
2645 assert(
impl &&
"expected AsmPrinter::printFloat to be overriden");
2650 assert(
impl &&
"expected AsmPrinter::printType to be overriden");
2651 impl->printType(type);
2655 assert(
impl &&
"expected AsmPrinter::printAttribute to be overriden");
2656 impl->printAttribute(attr);
2660 assert(
impl &&
"expected AsmPrinter::printAlias to be overriden");
2661 return impl->printAlias(attr);
2665 assert(
impl &&
"expected AsmPrinter::printAlias to be overriden");
2666 return impl->printAlias(type);
2671 "expected AsmPrinter::printAttributeWithoutType to be overriden");
2676 assert(
impl &&
"expected AsmPrinter::printKeywordOrString to be overriden");
2681 assert(
impl &&
"expected AsmPrinter::printSymbolName to be overriden");
2686 assert(
impl &&
"expected AsmPrinter::printResourceHandle to be overriden");
2687 impl->printResourceHandle(resource);
2696 printAffineExprInternal(expr, BindingStrength::Weak, printValueName);
2702 const char *binopSpelling =
nullptr;
2707 printValueName(pos,
true);
2715 printValueName(pos,
false);
2724 binopSpelling =
" + ";
2727 binopSpelling =
" * ";
2730 binopSpelling =
" floordiv ";
2733 binopSpelling =
" ceildiv ";
2736 binopSpelling =
" mod ";
2746 if (enclosingTightness == BindingStrength::Strong)
2752 rhsConst.getValue() == -1) {
2754 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
2755 if (enclosingTightness == BindingStrength::Strong)
2760 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);
2762 os << binopSpelling;
2763 printAffineExprInternal(rhsExpr, BindingStrength::Strong, printValueName);
2765 if (enclosingTightness == BindingStrength::Strong)
2771 if (enclosingTightness == BindingStrength::Strong)
2780 if (rrhs.getValue() == -1) {
2781 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
2785 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
2788 printAffineExprInternal(rhs.getLHS(), BindingStrength::Weak,
2792 if (enclosingTightness == BindingStrength::Strong)
2797 if (rrhs.getValue() < -1) {
2798 printAffineExprInternal(lhsExpr, BindingStrength::Weak,
2801 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,
2803 os <<
" * " << -rrhs.getValue();
2804 if (enclosingTightness == BindingStrength::Strong)
2814 if (rhsConst.getValue() < 0) {
2815 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
2816 os <<
" - " << -rhsConst.getValue();
2817 if (enclosingTightness == BindingStrength::Strong)
2823 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);
2826 printAffineExprInternal(rhsExpr, BindingStrength::Weak, printValueName);
2828 if (enclosingTightness == BindingStrength::Strong)
2833 printAffineExprInternal(expr, BindingStrength::Weak);
2834 isEq ? os <<
" == 0" : os <<
" >= 0";
2840 for (
int i = 0; i < (int)map.
getNumDims() - 1; ++i)
2841 os <<
'd' << i <<
", ";
2850 os <<
's' << i <<
", ";
2859 [&](
AffineExpr expr) { printAffineExpr(expr); });
2866 for (
unsigned i = 1; i < set.
getNumDims(); ++i)
2867 os <<
'd' << i - 1 <<
", ";
2876 os <<
's' << i <<
", ";
2885 for (
int i = 1; i < numConstraints; ++i) {
2889 if (numConstraints >= 1)
2890 printAffineConstraint(set.
getConstraint(numConstraints - 1),
2891 set.
isEq(numConstraints - 1));
2906 explicit OperationPrinter(raw_ostream &os,
AsmStateImpl &state)
2910 void printTopLevelOperation(
Operation *op);
2914 void printFullOpWithIndentAndLoc(
Operation *op);
2920 void printCustomOrGenericOp(
Operation *op)
override;
2922 void printGenericOp(
Operation *op,
bool printOpName)
override;
2925 void printBlockName(
Block *block);
2930 void print(
Block *block,
bool printBlockArgs =
true,
2931 bool printBlockTerminator =
true);
2934 void printValueID(
Value value,
bool printResultNo =
true,
2935 raw_ostream *streamOverride =
nullptr)
const;
2939 raw_ostream *streamOverride =
nullptr)
const;
2947 void printOptionalLocationSpecifier(
Location loc)
override {
2948 printTrailingLocation(loc);
2955 os.indent(currentIndent);
2959 void increaseIndent()
override { currentIndent += indentWidth; }
2962 void decreaseIndent()
override { currentIndent -= indentWidth; }
2971 bool omitType =
false)
override;
2974 void printOperand(
Value value)
override { printValueID(value); }
2975 void printOperand(
Value value, raw_ostream &os)
override {
2976 printValueID(value,
true, &os);
2984 void printOptionalAttrDictWithKeyword(
2992 void printSuccessor(
Block *successor)
override;
2996 void printSuccessorAndUseList(
Block *successor,
3001 bool printBlockTerminators,
bool printEmptyBlock)
override;
3013 void printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3028 void printValueUsers(
Value value);
3032 void printUserIDs(
Operation *user,
bool prefixComma =
false);
3040 using PrintFn =
function_ref<void(StringRef, ValueFn)>;
3042 ResourceBuilder(OperationPrinter &p, PrintFn printFn)
3043 : p(p), printFn(printFn) {}
3044 ~ResourceBuilder()
override =
default;
3046 void buildBool(StringRef key,
bool data)
final {
3047 printFn(key, [&](raw_ostream &os) { p.
os << (data ?
"true" :
"false"); });
3050 void buildString(StringRef key, StringRef data)
final {
3055 uint32_t dataAlignment)
final {
3056 printFn(key, [&](raw_ostream &os) {
3058 llvm::support::ulittle32_t dataAlignmentLE(dataAlignment);
3060 << llvm::toHex(StringRef(
reinterpret_cast<char *
>(&dataAlignmentLE),
3061 sizeof(dataAlignment)))
3062 << llvm::toHex(StringRef(data.data(), data.size())) <<
"\"";
3067 OperationPrinter &p;
3072 void printFileMetadataDictionary(
Operation *op);
3078 void printResourceFileMetadata(
function_ref<
void()> checkAddMetadataDict,
3089 const static unsigned indentWidth = 2;
3092 unsigned currentIndent = 0;
3096 void OperationPrinter::printTopLevelOperation(
Operation *op) {
3098 state.
getAliasState().printNonDeferredAliases(*
this, newLine);
3101 printFullOpWithIndentAndLoc(op);
3108 printFileMetadataDictionary(op);
3111 void OperationPrinter::printFileMetadataDictionary(
Operation *op) {
3112 bool sawMetadataEntry =
false;
3113 auto checkAddMetadataDict = [&] {
3114 if (!std::exchange(sawMetadataEntry,
true))
3115 os << newLine <<
"{-#" << newLine;
3119 printResourceFileMetadata(checkAddMetadataDict, op);
3122 if (sawMetadataEntry)
3123 os << newLine <<
"#-}" << newLine;
3126 void OperationPrinter::printResourceFileMetadata(
3129 bool hadResource =
false;
3130 auto processProvider = [&](StringRef dictName, StringRef name,
auto &provider,
3131 auto &&...providerArgs) {
3132 bool hadEntry =
false;
3133 auto printFn = [&](StringRef key, ResourceBuilder::ValueFn valueFn) {
3134 checkAddMetadataDict();
3137 if (!std::exchange(hadResource,
true))
3138 os <<
" " << dictName <<
"_resources: {" << newLine;
3140 if (!std::exchange(hadEntry,
true))
3141 os <<
" " << name <<
": {" << newLine;
3143 os <<
"," << newLine;
3145 os <<
" " << key <<
": ";
3148 ResourceBuilder entryBuilder(*
this, printFn);
3149 provider.buildResources(op, providerArgs..., entryBuilder);
3152 os << newLine <<
" }";
3159 StringRef name = interface.getDialect()->getNamespace();
3160 auto it = dialectResources.find(interface.getDialect());
3161 if (it != dialectResources.end())
3162 processProvider(
"dialect", name, interface, it->second);
3164 processProvider(
"dialect", name, interface,
3168 os << newLine <<
" }";
3172 hadResource =
false;
3174 processProvider(
"external", printer.getName(), printer);
3176 os << newLine <<
" }";
3184 void OperationPrinter::printRegionArgument(
BlockArgument arg,
3192 printOptionalAttrDict(argAttrs);
3194 printTrailingLocation(arg.
getLoc(),
false);
3197 void OperationPrinter::printFullOpWithIndentAndLoc(
Operation *op) {
3201 os.indent(currentIndent);
3203 printTrailingLocation(op->
getLoc());
3205 printUsersComment(op);
3208 void OperationPrinter::printFullOp(
Operation *op) {
3210 auto printResultGroup = [&](
size_t resultNo,
size_t resultCount) {
3211 printValueID(op->
getResult(resultNo),
false);
3212 if (resultCount > 1)
3213 os <<
':' << resultCount;
3218 if (!resultGroups.empty()) {
3221 interleaveComma(llvm::seq<int>(0, resultGroups.size() - 1), [&](
int i) {
3222 printResultGroup(resultGroups[i],
3223 resultGroups[i + 1] - resultGroups[i]);
3226 printResultGroup(resultGroups.back(), numResults - resultGroups.back());
3229 printResultGroup(0, numResults);
3235 printCustomOrGenericOp(op);
3238 void OperationPrinter::printUsersComment(
Operation *op) {
3242 printOperationID(op);
3243 }
else if (numResults && op->
use_empty()) {
3245 }
else if (numResults && !op->
use_empty()) {
3248 unsigned usedInNResults = 0;
3249 unsigned usedInNOperations = 0;
3252 if (userSet.insert(user).second) {
3253 ++usedInNOperations;
3254 usedInNResults += user->getNumResults();
3259 bool exactlyOneUniqueUse =
3260 usedInNResults <= 1 && usedInNOperations <= 1 && numResults == 1;
3261 os <<
" // " << (exactlyOneUniqueUse ?
"user" :
"users") <<
": ";
3262 bool shouldPrintBrackets = numResults > 1;
3263 auto printOpResult = [&](
OpResult opResult) {
3264 if (shouldPrintBrackets)
3266 printValueUsers(opResult);
3267 if (shouldPrintBrackets)
3271 interleaveComma(op->
getResults(), printOpResult);
3275 void OperationPrinter::printUsersComment(
BlockArgument arg) {
3281 os <<
" is used by ";
3282 printValueUsers(arg);
3287 void OperationPrinter::printValueUsers(
Value value) {
3295 if (userSet.insert(user).second)
3296 printUserIDs(user, index);
3300 void OperationPrinter::printUserIDs(
Operation *user,
bool prefixComma) {
3305 printOperationID(user);
3308 [
this](
Value result) { printValueID(result); });
3312 void OperationPrinter::printCustomOrGenericOp(
Operation *op) {
3318 opInfo->printAssembly(op, *
this, defaultDialectStack.back());
3323 if (
auto opPrinter = dialect->getOperationPrinter(op)) {
3328 if (name.count(
'.') == 1)
3329 name.consume_front((defaultDialectStack.back() +
".").str());
3333 opPrinter(op, *
this);
3340 printGenericOp(op,
true);
3343 void OperationPrinter::printGenericOp(
Operation *op,
bool printOpName) {
3347 interleaveComma(op->
getOperands(), [&](
Value value) { printValueID(value); });
3354 [&](
Block *successor) { printBlockName(successor); });
3362 printRegion(region, true,
3369 printOptionalAttrDict(attrs);
3376 void OperationPrinter::printBlockName(
Block *block) {
3381 bool printBlockTerminator) {
3383 if (printBlockArgs) {
3384 os.indent(currentIndent);
3385 printBlockName(block);
3393 printType(arg.getType());
3395 printTrailingLocation(arg.getLoc(), false);
3403 os <<
" // block is not in a region!";
3406 os <<
" // no predecessors";
3409 printBlockName(pred);
3416 llvm::sort(predIDs, [](BlockInfo lhs, BlockInfo rhs) {
3417 return lhs.ordering < rhs.ordering;
3420 os <<
" // " << predIDs.size() <<
" preds: ";
3422 interleaveComma(predIDs, [&](BlockInfo pred) { os << pred.name; });
3427 currentIndent += indentWidth;
3431 os.indent(currentIndent);
3432 printUsersComment(arg);
3436 bool hasTerminator =
3438 auto range = llvm::make_range(
3440 std::prev(block->
end(),
3441 (!hasTerminator || printBlockTerminator) ? 0 : 1));
3442 for (
auto &op : range) {
3443 printFullOpWithIndentAndLoc(&op);
3446 currentIndent -= indentWidth;
3449 void OperationPrinter::printValueID(
Value value,
bool printResultNo,
3450 raw_ostream *streamOverride)
const {
3452 streamOverride ? *streamOverride : os);
3455 void OperationPrinter::printOperationID(
Operation *op,
3456 raw_ostream *streamOverride)
const {
3457 state.
getSSANameState().printOperationID(op, streamOverride ? *streamOverride
3461 void OperationPrinter::printSuccessor(
Block *successor) {
3462 printBlockName(successor);
3465 void OperationPrinter::printSuccessorAndUseList(
Block *successor,
3467 printBlockName(successor);
3468 if (succOperands.empty())
3472 interleaveComma(succOperands,
3473 [
this](
Value operand) { printValueID(operand); });
3475 interleaveComma(succOperands,
3481 bool printBlockTerminators,
3482 bool printEmptyBlock) {
3487 os <<
"{" << newLine;
3488 if (!region.
empty()) {
3489 auto restoreDefaultDialect =
3490 llvm::make_scope_exit([&]() { defaultDialectStack.pop_back(); });
3491 if (
auto iface = dyn_cast<OpAsmOpInterface>(region.
getParentOp()))
3492 defaultDialectStack.push_back(iface.getDefaultDialect());
3494 defaultDialectStack.push_back(
"");
3496 auto *entryBlock = ®ion.
front();
3500 bool shouldAlwaysPrintBlockHeader =
3501 (printEmptyBlock && entryBlock->empty()) ||
3502 (printEntryBlockArgs && entryBlock->getNumArguments() != 0);
3503 print(entryBlock, shouldAlwaysPrintBlockHeader, printBlockTerminators);
3504 for (
auto &b : llvm::drop_begin(region.
getBlocks(), 1))
3507 os.indent(currentIndent) <<
"}";
3510 void OperationPrinter::printAffineMapOfSSAIds(AffineMapAttr mapAttr,
3514 auto printValueName = [&](
unsigned pos,
bool isSymbol) {
3515 unsigned index = isSymbol ? numDims + pos : pos;
3516 assert(index < operands.size());
3519 printValueID(operands[index]);
3525 printAffineExpr(expr, printValueName);
3529 void OperationPrinter::printAffineExprOfSSAIds(
AffineExpr expr,
3532 auto printValueName = [&](
unsigned pos,
bool isSymbol) {
3534 return printValueID(dimOperands[pos]);
3536 printValueID(symOperands[pos]);
3539 printAffineExpr(expr, printValueName);
3548 os <<
"<<NULL ATTRIBUTE>>";
3553 print(os, state, elideType);
3559 : AttrTypeElision::Never);
3563 print(llvm::errs());
3564 llvm::errs() <<
"\n";
3569 os <<
"<<NULL TYPE>>";
3581 print(llvm::errs());
3582 llvm::errs() <<
"\n";
3586 print(llvm::errs());
3587 llvm::errs() <<
"\n";
3591 print(llvm::errs());
3592 llvm::errs() <<
"\n";
3597 os <<
"<<NULL AFFINE EXPR>>";
3605 print(llvm::errs());
3606 llvm::errs() <<
"\n";
3611 os <<
"<<NULL AFFINE MAP>>";
3626 os <<
"<<NULL VALUE>>";
3630 if (
auto *op = getDefiningOp())
3631 return op->
print(os, flags);
3634 os <<
"<block argument> of type '" << arg.
getType()
3639 os <<
"<<NULL VALUE>>";
3643 if (
auto *op = getDefiningOp())
3644 return op->
print(os, state);
3648 os <<
"<block argument> of type '" << arg.
getType()
3653 print(llvm::errs());
3654 llvm::errs() <<
"\n";
3687 OperationPrinter printer(os, state.
getImpl());
3690 printer.printTopLevelOperation(
this);
3692 printer.printFullOpWithIndentAndLoc(
this);
3698 llvm::errs() <<
"\n";
3704 os <<
"<<UNLINKED BLOCK>>\n";
3715 OperationPrinter(os, state.
getImpl()).print(
this);
3724 os <<
"<<UNLINKED BLOCK>>\n";
3728 printAsOperand(os, state);
3731 OperationPrinter printer(os, state.
getImpl());
3732 printer.printBlockName(
this);
static StringRef sanitizeIdentifier(StringRef name, SmallString< 16 > &buffer, StringRef allowedPunctChars="$._-", bool allowTrailingDigit=true)
Sanitize the given name such that it can be used as a valid identifier.
static void printSymbolReference(StringRef symbolRef, raw_ostream &os)
Print the given string as a symbol reference.
static bool shouldPrintElementsAttrWithHex(int64_t numElements)
Returns true if an ElementsAttr with the given number of elements should be printed with hex.
static llvm::ManagedStatic< AsmPrinterOptions > clOptions
static 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 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 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)
Affine binary operation expression.
An integer constant appearing in affine expression.
A dimensional identifier appearing in an affine expression.
Base type for affine expression.
AffineExprKind getKind() const
Return the classification for this type.
void print(raw_ostream &os) const
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
void print(raw_ostream &os) const
A symbolic identifier appearing in an affine expression.
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
Impl(raw_ostream &os, AsmStateImpl &state)
BindingStrength
This enum is used to represent the binding strength of the enclosing context that an AffineExprStorag...
void printHexString(StringRef str)
Print a hex string, wrapped with "".
void printDenseArrayAttr(DenseArrayAttr attr)
Print a dense array attribute.
void printDenseElementsAttr(DenseElementsAttr attr, bool allowHex)
Print a dense elements attribute.
void printAttribute(Attribute attr, AttrTypeElision typeElision=AttrTypeElision::Never)
Print the given attribute or an alias.
OpPrintingFlags printerFlags
A set of flags to control the printer's behavior.
raw_ostream & os
The output stream for the printer.
void printResourceHandle(const AsmDialectResourceHandle &resource)
Print a reference to the given resource that is owned by the given dialect.
raw_ostream & getStream()
Returns the output stream of the printer.
LogicalResult printAlias(Attribute attr)
Print the alias for the given attribute, return failure if no alias could be printed.
void printDialectAttribute(Attribute attr)
void interleaveComma(const Container &c, UnaryFunctor eachFn) const
void printDialectType(Type type)
void printLocation(LocationAttr loc, bool allowAlias=false)
Print the given location to the stream.
AsmStateImpl & state
An underlying assembly printer state.
void printAffineMap(AffineMap map)
void printTrailingLocation(Location loc, bool allowAlias=true)
void printAffineExprInternal(AffineExpr expr, BindingStrength enclosingTightness, function_ref< void(unsigned, bool)> printValueName=nullptr)
void printEscapedString(StringRef str)
Print an escaped string, wrapped with "".
void printAffineExpr(AffineExpr expr, function_ref< void(unsigned, bool)> printValueName=nullptr)
void printDenseStringElementsAttr(DenseStringElementsAttr attr)
Print a dense string elements attribute.
void printAttributeImpl(Attribute attr, AttrTypeElision typeElision=AttrTypeElision::Never)
Print the given attribute without considering an alias.
void printAffineConstraint(AffineExpr expr, bool isEq)
void printDenseIntOrFPElementsAttr(DenseIntOrFPElementsAttr attr, bool allowHex)
Print a dense elements attribute.
AttrTypeElision
This enum describes the different kinds of elision for the type of an attribute when printing it.
@ May
The type may be elided when it matches the default used in the parser (for example i64 is the default...
@ Never
The type must not be elided,.
@ Must
The type must be elided.
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.
void printFunctionalType(InputRangeT &&inputs, ResultRangeT &&results)
Print the two given type ranges in a functional form.
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 printAttribute(Attribute attr)
virtual raw_ostream & getStream() const
Return the raw output stream used by this printer.
virtual void printResourceHandle(const AsmDialectResourceHandle &resource)
Print a handle to the given dialect resource.
virtual void printFloat(const APFloat &value)
Print the given floating point value in a stabilized form that can be roundtripped through the IR.
This class is used to build resource entries for use by the printer.
virtual void buildString(StringRef key, StringRef data)=0
Build a resource entry represented by the given human-readable string value.
virtual void buildBool(StringRef key, bool data)=0
Build a resource entry represented by the given bool.
virtual void buildBlob(StringRef key, ArrayRef< char > data, uint32_t dataAlignment)=0
Build an resource entry represented by the given binary blob data.
This class represents an instance of a resource parser.
static std::unique_ptr< AsmResourcePrinter > fromCallable(StringRef name, CallableT &&printFn)
Return a resource printer implemented via the given callable, whose form should match that of buildRe...
This class provides management for the lifetime of the state used when printing the IR.
detail::AsmStateImpl & getImpl()
Return an instance of the internal implementation.
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.
void print(raw_ostream &os, bool elideType=false) const
Print the attribute.
bool isa() const
Casting utility functions.
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.
Block * getOwner() const
Returns the block that owns this argument.
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.
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
Block * getSinglePredecessor()
If this block has exactly one predecessor, return it.
void printAsOperand(raw_ostream &os, bool printType=true)
Print out the name of the block without printing its body.
iterator_range< pred_iterator > getPredecessors()
void print(raw_ostream &os)
BlockArgListType getArguments()
bool isEntryBlock()
Return if this block is the entry block in the parent region.
bool hasNoPredecessors()
Return true if this block has no predecessors.
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.
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
void print(raw_ostream &os) 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...
bool isa() const
Type casting utilities on the underlying location.
MLIRContext is the top-level object for a collection of MLIR operations.
NamedAttribute represents a combination of a name and an Attribute value.
Attribute getValue() const
Return the value of the attribute.
virtual std::string getResourceKey(const AsmDialectResourceHandle &handle) const
Return a key to use for the given resource.
virtual LogicalResult parseResource(AsmParsedResourceEntry &entry) const
Hook for parsing resource entries.
AliasResult
Holds the result of getAlias hook call.
@ FinalAlias
An alias was provided and it should be used (no other hooks will be checked).
@ NoAlias
The object (type or attribute) is not supported by the hook and an alias was not provided.
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
void printFunctionalType(Operation *op)
Print the complete type of an operation in functional form.
Set of flags used to control the behavior of the various IR print methods (e.g.
bool shouldElideElementsAttr(ElementsAttr attr) const
Return if the given ElementsAttr should be elided.
std::optional< int64_t > getLargeElementsAttrLimit() const
Return the size limit for printing large ElementsAttr.
bool shouldAssumeVerified() const
Return if operation verification should be skipped.
OpPrintingFlags & printValueUsers()
Print users of values as comments.
bool shouldUseLocalScope() const
Return if the printer should use local scope when dumping the IR.
OpPrintingFlags & skipRegions()
Skip printing regions.
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.
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 & assumeVerified()
Do not verify the operation when using custom operation printers.
OpPrintingFlags & printGenericOpForm()
Always print operations in the generic form.
OpPrintingFlags & useLocalScope()
Use local scope when printing the operation.
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.
unsigned getNumRegions()
Returns the number of regions held by this operation.
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()
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
ArrayRef< NamedAttribute > getAttrs()
Return all of the attributes on this operation.
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
OperationName getName()
The name of an operation is the key identifier for it.
operand_type_range getOperandTypes()
result_type_range getResultTypes()
operand_range getOperands()
Returns an iterator on the underlying Value's.
user_range getUsers()
Returns a range of all users.
SuccessorRange getSuccessors()
result_range getResults()
unsigned getNumResults()
Return the number of results held by this operation.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
iterator_range< OpIterator > getOps()
Operation * getParentOp()
Return the parent operation this region is attached to.
unsigned getNumArguments()
BlockListType & getBlocks()
BlockArgument getArgument(unsigned i)
This diagnostic handler is a simple RAII class that registers and erases a diagnostic handler on a gi...
An attribute that represents a reference to a splat vector or tensor constant, meaning all of the ele...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
void print(raw_ostream &os) const
Print the current type.
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)
Type getType() const
Return the type of this value.
void printAsOperand(raw_ostream &os, AsmState &state)
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.
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)
void printType(Type type, AsmPrinter &printer)
Prints an LLVM Dialect type.
Detect if any of the given parameter types has a sub-element handler.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
bool operator<(const Fraction &x, const Fraction &y)
This header declares functions that assit transformations in the MemRef dialect.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
StringRef toString(AsmResourceEntryKind kind)
bool succeeded(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a success value.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
@ CeilDiv
RHS of ceildiv is always a constant or a symbolic expression.
@ Mul
RHS of mul is always a constant or a symbolic expression.
@ Mod
RHS of mod is always a constant or a symbolic expression with a positive value.
@ DimId
Dimensional identifier.
@ FloorDiv
RHS of floordiv is always a constant or a symbolic expression.
@ Constant
Constant integer.
@ SymbolId
Symbolic identifier.
void registerAsmPrinterCLOptions()
Register a set of useful command-line options that can be used to configure various flags within the ...
AsmResourceEntryKind
This enum represents the different kinds of resource values.
@ Blob
A blob of data with an accompanying alignment.
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
raw_ostream & operator<<(raw_ostream &os, const AliasResult &result)
This class represents an efficient way to signal success or failure.
This trait is used to determine if a storage user, like Type, is mutable or not.