MLIR: lib/IR/AsmPrinter.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

31 #include "llvm/ADT/APFloat.h"

32 #include "llvm/ADT/ArrayRef.h"

33 #include "llvm/ADT/DenseMap.h"

34 #include "llvm/ADT/MapVector.h"

35 #include "llvm/ADT/STLExtras.h"

36 #include "llvm/ADT/ScopeExit.h"

37 #include "llvm/ADT/ScopedHashTable.h"

38 #include "llvm/ADT/SetVector.h"

39 #include "llvm/ADT/SmallString.h"

40 #include "llvm/ADT/StringExtras.h"

41 #include "llvm/ADT/StringSet.h"

42 #include "llvm/ADT/TypeSwitch.h"

43 #include "llvm/Support/CommandLine.h"

44 #include "llvm/Support/Debug.h"

45 #include "llvm/Support/Endian.h"

46 #include "llvm/Support/ManagedStatic.h"

47 #include "llvm/Support/Regex.h"

48 #include "llvm/Support/SaveAndRestore.h"

49 #include "llvm/Support/Threading.h"

50 #include "llvm/Support/raw_ostream.h"

51 #include <type_traits>

52

53 #include

54 #include

55

56 using namespace mlir;

58

59 #define DEBUG_TYPE "mlir-asm-printer"

60

62

64

65

66

67

68

72

74

75

76

77

80 [&]() { return parseType(result.emplace_back()); });

81 }

82

83

84

85

86

88

89

90

91

92

94

96 auto &os = getStream();

97 os << '(';

98 llvm::interleaveComma(op->getOperands(), os, [&](Value operand) {

99

100 *this << (operand ? operand.getType() : Type());

101 });

102 os << ") -> ";

103

104

105

109 wrapped = true;

110

111 if (wrapped)

112 os << '(';

113

114 llvm::interleaveComma(op->getResults(), os, [&](const OpResult &result) {

115

116 *this << (result ? result.getType() : Type());

117 });

118

119 if (wrapped)

120 os << ')';

121 }

122

123

124

125

126

127

128 #include "mlir/IR/OpAsmAttrInterface.cpp.inc"

129 #include "mlir/IR/OpAsmOpInterface.cpp.inc"

130 #include "mlir/IR/OpAsmTypeInterface.cpp.inc"

131

132 LogicalResult

134 return entry.emitError() << "unknown 'resource' key '" << entry.getKey()

135 << "' for dialect '" << getDialect()->getNamespace()

136 << "'";

137 }

138

139

140

141

142

143 namespace {

144

145

146

147 struct AsmPrinterOptions {

148 llvm:🆑:opt<int64_t> printElementsAttrWithHexIfLarger{

149 "mlir-print-elementsattrs-with-hex-if-larger",

150 llvm:🆑:desc(

151 "Print DenseElementsAttrs with a hex string that have "

152 "more elements than the given upper limit (use -1 to disable)")};

153

154 llvm:🆑:opt elideElementsAttrIfLarger{

155 "mlir-elide-elementsattrs-if-larger",

156 llvm:🆑:desc("Elide ElementsAttrs with \"...\" that have "

157 "more elements than the given upper limit")};

158

159 llvm:🆑:opt elideResourceStringsIfLarger{

160 "mlir-elide-resource-strings-if-larger",

161 llvm:🆑:desc(

162 "Elide printing value of resources if string is too long in chars.")};

163

164 llvm:🆑:opt printDebugInfoOpt{

165 "mlir-print-debuginfo", llvm:🆑:init(false),

166 llvm:🆑:desc("Print debug info in MLIR output")};

167

168 llvm:🆑:opt printPrettyDebugInfoOpt{

169 "mlir-pretty-debuginfo", llvm:🆑:init(false),

170 llvm:🆑:desc("Print pretty debug info in MLIR output")};

171

172

173

174 llvm:🆑:opt printGenericOpFormOpt{

175 "mlir-print-op-generic", llvm:🆑:init(false),

176 llvm:🆑:desc("Print the generic op form"), llvm:🆑:Hidden};

177

178 llvm:🆑:opt assumeVerifiedOpt{

179 "mlir-print-assume-verified", llvm:🆑:init(false),

180 llvm:🆑:desc("Skip op verification when using custom printers"),

181 llvm:🆑:Hidden};

182

183 llvm:🆑:opt printLocalScopeOpt{

184 "mlir-print-local-scope", llvm:🆑:init(false),

185 llvm:🆑:desc("Print with local scope and inline information (eliding "

186 "aliases for attributes, types, and locations)")};

187

188 llvm:🆑:opt skipRegionsOpt{

189 "mlir-print-skip-regions", llvm:🆑:init(false),

190 llvm:🆑:desc("Skip regions when printing ops.")};

191

192 llvm:🆑:opt printValueUsers{

193 "mlir-print-value-users", llvm:🆑:init(false),

194 llvm:🆑:desc(

195 "Print users of operation results and block arguments as a comment")};

196

197 llvm:🆑:opt printUniqueSSAIDs{

198 "mlir-print-unique-ssa-ids", llvm:🆑:init(false),

199 llvm:🆑:desc("Print unique SSA ID numbers for values, block arguments "

200 "and naming conflicts across all regions")};

201

202 llvm:🆑:opt useNameLocAsPrefix{

203 "mlir-use-nameloc-as-prefix", llvm:🆑:init(false),

204 llvm:🆑:desc("Print SSA IDs using NameLocs as prefixes")};

205 };

206 }

207

208 static llvm::ManagedStatic clOptions;

209

210

211

213

215 }

216

217

219 : printDebugInfoFlag(false), printDebugInfoPrettyFormFlag(false),

220 printGenericOpFormFlag(false), skipRegionsFlag(false),

221 assumeVerifiedFlag(false), printLocalScope(false),

222 printValueUsersFlag(false), printUniqueSSAIDsFlag(false),

223 useNameLocAsPrefix(false) {

224

226 return;

227 if (clOptions->elideElementsAttrIfLarger.getNumOccurrences())

228 elementsAttrElementLimit = clOptions->elideElementsAttrIfLarger;

229 if (clOptions->printElementsAttrWithHexIfLarger.getNumOccurrences())

230 elementsAttrHexElementLimit =

231 clOptions->printElementsAttrWithHexIfLarger.getValue();

232 if (clOptions->elideResourceStringsIfLarger.getNumOccurrences())

233 resourceStringCharLimit = clOptions->elideResourceStringsIfLarger;

234 printDebugInfoFlag = clOptions->printDebugInfoOpt;

235 printDebugInfoPrettyFormFlag = clOptions->printPrettyDebugInfoOpt;

236 printGenericOpFormFlag = clOptions->printGenericOpFormOpt;

237 assumeVerifiedFlag = clOptions->assumeVerifiedOpt;

238 printLocalScope = clOptions->printLocalScopeOpt;

239 skipRegionsFlag = clOptions->skipRegionsOpt;

240 printValueUsersFlag = clOptions->printValueUsers;

241 printUniqueSSAIDsFlag = clOptions->printUniqueSSAIDs;

242 useNameLocAsPrefix = clOptions->useNameLocAsPrefix;

243 }

244

245

246

247

248

251 elementsAttrElementLimit = largeElementLimit;

252 return *this;

253 }

254

257 elementsAttrHexElementLimit = largeElementLimit;

258 return *this;

259 }

260

263 resourceStringCharLimit = largeResourceLimit;

264 return *this;

265 }

266

267

268

270 bool prettyForm) {

271 printDebugInfoFlag = enable;

272 printDebugInfoPrettyFormFlag = prettyForm;

273 return *this;

274 }

275

276

278 printGenericOpFormFlag = enable;

279 return *this;

280 }

281

282

284 skipRegionsFlag = skip;

285 return *this;

286 }

287

288

290 assumeVerifiedFlag = enable;

291 return *this;

292 }

293

294

295

296

298 printLocalScope = enable;

299 return *this;

300 }

301

302

304 printValueUsersFlag = enable;

305 return *this;

306 }

307

308

309

311 printUniqueSSAIDsFlag = enable;

312 return *this;

313 }

314

315

317 return elementsAttrElementLimit &&

318 *elementsAttrElementLimit < int64_t(attr.getNumElements()) &&

319 !llvm::isa(attr);

320 }

321

322

324

325 return (elementsAttrHexElementLimit != -1) &&

326 (elementsAttrHexElementLimit < int64_t(attr.getNumElements())) &&

327 !llvm::isa(attr);

328 }

329

331 useNameLocAsPrefix = enable;

332 return *this;

333 }

334

335

337 return elementsAttrElementLimit;

338 }

339

340

342 return elementsAttrHexElementLimit;

343 }

344

345

347 return resourceStringCharLimit;

348 }

349

350

352 return printDebugInfoFlag;

353 }

354

355

357 return printDebugInfoPrettyFormFlag;

358 }

359

360

362 return printGenericOpFormFlag;

363 }

364

365

367

368

370 return assumeVerifiedFlag;

371 }

372

373

375

376

378 return printValueUsersFlag;

379 }

380

381

384 }

385

386

388 return useNameLocAsPrefix;

389 }

390

391

392

393

394

395 namespace {

396

397

398

399 struct NewLineCounter {

400 unsigned curLine = 1;

401 };

402

403 static raw_ostream &operator<<(raw_ostream &os, NewLineCounter &newLine) {

404 ++newLine.curLine;

405 return os << '\n';

406 }

407 }

408

409

410

411

412

413 namespace mlir {

415 public:

418

419

421

422 template <typename Container, typename UnaryFunctor>

423 inline void interleaveComma(const Container &c, UnaryFunctor eachFn) const {

424 llvm::interleaveComma(c, os, eachFn);

425 }

426

427

428

430

432

433

435

437 };

438

439

442

445

446

447

449

450

452

454

455

456

458

459

460

462

463

464

466

468 void

470 function_ref<void(unsigned, bool)> printValueName = nullptr);

473

475

477

479

480 protected:

483 bool withKeyword = false);

487 bool isTopLevel = false);

488

489

490

492

493

495

496

497

499 bool allowHex);

500

501

503

506

507

509

510

513

514

515

516

518 Weak,

519 Strong,

520 };

523 function_ref<void(unsigned, bool)> printValueName = nullptr);

524

525

527

528

530

531

533

534

536 };

537 }

538

539

540

541

542

543 namespace {

544

545 class SymbolAlias {

546 public:

547 SymbolAlias(StringRef name, uint32_t suffixIndex, bool isType,

548 bool isDeferrable)

549 : name(name), suffixIndex(suffixIndex), isType(isType),

550 isDeferrable(isDeferrable) {}

551

552

553 void print(raw_ostream &os) const {

554 os << (isType ? "!" : "#") << name;

555 if (suffixIndex) {

556 if (isdigit(name.back()))

557 os << '_';

558 os << suffixIndex;

559 }

560 }

561

562

563 bool isTypeAlias() const { return isType; }

564

565

566 bool canBeDeferred() const { return isDeferrable; }

567

568 private:

569

570 StringRef name;

571

572 uint32_t suffixIndex : 30;

573

574 bool isType : 1;

575

576 bool isDeferrable : 1;

577

578 public:

579

580 bool isPrinted = false;

581 };

582

583

584

585

586 class AliasInitializer {

587 public:

588 AliasInitializer(

590 llvm::BumpPtrAllocator &aliasAllocator)

591 : interfaces(interfaces), aliasAllocator(aliasAllocator),

592 aliasOS(aliasBuffer) {}

593

595 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias);

596

597

598

599

600

601

602

603 std::pair<size_t, size_t> visit(Attribute attr, bool canBeDeferred = false,

604 bool elideType = false) {

605 return visitImpl(attr, aliases, canBeDeferred, elideType);

606 }

607

608

609

610

611

612 std::pair<size_t, size_t> visit(Type type, bool canBeDeferred = false) {

613 return visitImpl(type, aliases, canBeDeferred);

614 }

615

616 private:

617 struct InProgressAliasInfo {

618 InProgressAliasInfo()

619 : aliasDepth(0), isType(false), canBeDeferred(false) {}

620 InProgressAliasInfo(StringRef alias)

621 : alias(alias), aliasDepth(1), isType(false), canBeDeferred(false) {}

622

623 bool operator<(const InProgressAliasInfo &rhs) const {

624

625 if (aliasDepth != rhs.aliasDepth)

626 return aliasDepth < rhs.aliasDepth;

627 if (isType != rhs.isType)

628 return isType;

629 return alias < rhs.alias;

630 }

631

632

633

634 std::optional alias;

635

636

637 unsigned aliasDepth : 30;

638

639 bool isType : 1;

640

641 bool canBeDeferred : 1;

642

644 };

645

646

647

648

649

650

651 template <typename T, typename... PrintArgs>

652 std::pair<size_t, size_t>

653 visitImpl(T value,

654 llvm::MapVector<const void *, InProgressAliasInfo> &aliases,

655 bool canBeDeferred, PrintArgs &&...printArgs);

656

657

658 void markAliasNonDeferrable(size_t aliasIndex);

659

660

661

662 template

663 void generateAlias(T symbol, InProgressAliasInfo &alias, bool canBeDeferred);

664

665

666

667 static unsigned

668 uniqueAliasNameIndex(StringRef alias, llvm::StringMap &nameCounts,

670

671

672

673 static void initializeAliases(

674 llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,

675 llvm::MapVector<const void *, SymbolAlias> &symbolToAlias);

676

677

679

680

681 llvm::BumpPtrAllocator &aliasAllocator;

682

683

684 llvm::MapVector<const void *, InProgressAliasInfo> aliases;

685

686

688 llvm::raw_svector_ostream aliasOS;

689 };

690

691

692

693

694

695

696 class DummyAliasOperationPrinter : private OpAsmPrinter {

697 public:

698 explicit DummyAliasOperationPrinter(const OpPrintingFlags &printerFlags,

699 AliasInitializer &initializer)

700 : printerFlags(printerFlags), initializer(initializer) {}

701

702

703

704 void printCustomOrGenericOp(Operation *op) override {

705

706 if (printerFlags.shouldPrintDebugInfo())

707 initializer.visit(op->getLoc(), true);

708

709

710 if (!printerFlags.shouldPrintGenericOpForm()) {

712 return;

713 }

714

715

716 printGenericOp(op);

717 }

718

719 private:

720

721 void printGenericOp(Operation *op, bool printOpName = true) override {

722

723 if (!printerFlags.shouldSkipRegions()) {

725 printRegion(region, true,

726 true);

727 }

728

729

734

735

737 printAttribute(attr.getValue());

738 }

739

740

741

742

743 void print(Block *block, bool printBlockArgs = true,

744 bool printBlockTerminator = true) {

745

746

747 if (printBlockArgs) {

750

751

752 if (printerFlags.shouldPrintDebugInfo())

753

754 initializer.visit(arg.getLoc(), false);

755 }

756 }

757

758

759

760 bool hasTerminator =

762 auto range = llvm::make_range(

764 std::prev(block->end(),

765 (!hasTerminator || printBlockTerminator) ? 0 : 1));

767 printCustomOrGenericOp(&op);

768 }

769

770

772 bool printBlockTerminators,

773 bool printEmptyBlock = false) override {

774 if (region.empty())

775 return;

776 if (printerFlags.shouldSkipRegions()) {

777 os << "{...}";

778 return;

779 }

780

781 auto *entryBlock = &region.front();

782 print(entryBlock, printEntryBlockArgs, printBlockTerminators);

783 for (Block &b : llvm::drop_begin(region, 1))

785 }

786

788 bool omitType) override {

790

791 if (printerFlags.shouldPrintDebugInfo())

792

793 initializer.visit(arg.getLoc(), false);

794 }

795

796

797 void printType(Type type) override { initializer.visit(type); }

798

799

800 void printAttribute(Attribute attr) override { initializer.visit(attr); }

801 void printAttributeWithoutType(Attribute attr) override {

802 printAttribute(attr);

803 }

804 LogicalResult printAlias(Attribute attr) override {

805 initializer.visit(attr);

806 return success();

807 }

808 LogicalResult printAlias(Type type) override {

809 initializer.visit(type);

810 return success();

811 }

812

813

814 void printOptionalLocationSpecifier(Location loc) override {

815 printAttribute(loc);

816 }

817

818

819

822 if (attrs.empty())

823 return;

824 if (elidedAttrs.empty()) {

826 printAttribute(attr.getValue());

827 return;

828 }

829 llvm::SmallDenseSet elidedAttrsSet(elidedAttrs.begin(),

830 elidedAttrs.end());

832 if (!elidedAttrsSet.contains(attr.getName().strref()))

833 printAttribute(attr.getValue());

834 }

835 void printOptionalAttrDictWithKeyword(

838 printOptionalAttrDict(attrs, elidedAttrs);

839 }

840

841

842

843 raw_ostream &getStream() const override { return os; }

844

845

846

847 void printFloat(const APFloat &) override {}

848 void printAffineMapOfSSAIds(AffineMapAttr, ValueRange) override {}

851 void increaseIndent() override {}

852 void decreaseIndent() override {}

853 void printOperand(Value) override {}

854 void printOperand(Value, raw_ostream &os) override {

855

856

857

858 os << "%";

859 }

863 void printSymbolName(StringRef) override {}

864 void printSuccessor(Block *) override {}

865 void printSuccessorAndUseList(Block *, ValueRange) override {}

867

868

870

871

872 AliasInitializer &initializer;

873

874

875 mutable llvm::raw_null_ostream os;

876 };

877

879 public:

880 explicit DummyAliasDialectAsmPrinter(AliasInitializer &initializer,

881 bool canBeDeferred,

883 : initializer(initializer), canBeDeferred(canBeDeferred),

884 childIndices(childIndices) {}

885

886

887

888

889 template <typename T, typename... PrintArgs>

890 size_t printAndVisitNestedAliases(T value, PrintArgs &&...printArgs) {

891 printAndVisitNestedAliasesImpl(value, printArgs...);

892 return maxAliasDepth;

893 }

894

895 private:

896

897

898 void printAndVisitNestedAliasesImpl(Attribute attr, bool elideType) {

899 if (!isa(attr.getDialect())) {

901

902

903 } else if (llvm::isa<AffineMapAttr, DenseArrayAttr, FloatAttr, IntegerAttr,

904 IntegerSetAttr, UnitAttr>(attr)) {

905 return;

906 } else if (auto distinctAttr = dyn_cast(attr)) {

907 printAttribute(distinctAttr.getReferencedAttr());

908 } else if (auto dictAttr = dyn_cast(attr)) {

910 printAttribute(nestedAttr.getName());

911 printAttribute(nestedAttr.getValue());

912 }

913 } else if (auto arrayAttr = dyn_cast(attr)) {

914 for (Attribute nestedAttr : arrayAttr.getValue())

915 printAttribute(nestedAttr);

916 } else if (auto typeAttr = dyn_cast(attr)) {

918 } else if (auto locAttr = dyn_cast(attr)) {

919 printAttribute(locAttr.getFallbackLocation());

920 } else if (auto locAttr = dyn_cast(attr)) {

921 if (!isa(locAttr.getChildLoc()))

922 printAttribute(locAttr.getChildLoc());

923 } else if (auto locAttr = dyn_cast(attr)) {

924 printAttribute(locAttr.getCallee());

925 printAttribute(locAttr.getCaller());

926 } else if (auto locAttr = dyn_cast(attr)) {

927 if (Attribute metadata = locAttr.getMetadata())

928 printAttribute(metadata);

929 for (Location nestedLoc : locAttr.getLocations())

930 printAttribute(nestedLoc);

931 }

932

933

934 if (!elideType) {

935 if (auto typedAttr = llvm::dyn_cast(attr)) {

936 Type attrType = typedAttr.getType();

937 if (!llvm::isa(attrType))

939 }

940 }

941 }

942 void printAndVisitNestedAliasesImpl(Type type) {

943 if (!isa(type.getDialect()))

945

946

947 if (auto memrefTy = llvm::dyn_cast(type)) {

948 printType(memrefTy.getElementType());

949 MemRefLayoutAttrInterface layout = memrefTy.getLayout();

950 if (!llvm::isa(layout) || !layout.isIdentity())

951 printAttribute(memrefTy.getLayout());

952 if (memrefTy.getMemorySpace())

953 printAttribute(memrefTy.getMemorySpace());

954 return;

955 }

956

957

958 auto visitFn = [&](auto element) {

959 if (element)

960 (void)printAlias(element);

961 };

963 }

964

965

967 recordAliasResult(initializer.visit(type, canBeDeferred));

968 }

969

970

971 void printAttribute(Attribute attr) override {

972 recordAliasResult(initializer.visit(attr, canBeDeferred));

973 }

974 void printAttributeWithoutType(Attribute attr) override {

975 recordAliasResult(

976 initializer.visit(attr, canBeDeferred, true));

977 }

978 LogicalResult printAlias(Attribute attr) override {

979 printAttribute(attr);

980 return success();

981 }

982 LogicalResult printAlias(Type type) override {

984 return success();

985 }

986

987

988 void recordAliasResult(std::pair<size_t, size_t> aliasDepthAndIndex) {

989 childIndices.push_back(aliasDepthAndIndex.second);

990 if (aliasDepthAndIndex.first > maxAliasDepth)

991 maxAliasDepth = aliasDepthAndIndex.first;

992 }

993

994

995

996 raw_ostream &getStream() const override { return os; }

997

998

999

1000 void printFloat(const APFloat &) override {}

1003 void printSymbolName(StringRef) override {}

1005

1006 LogicalResult pushCyclicPrinting(const void *opaquePointer) override {

1007 return success(cyclicPrintingStack.insert(opaquePointer));

1008 }

1009

1010 void popCyclicPrinting() override { cyclicPrintingStack.pop_back(); }

1011

1012

1013

1015

1016

1017 AliasInitializer &initializer;

1018

1019

1020 bool canBeDeferred;

1021

1022

1024

1025

1026 size_t maxAliasDepth = 0;

1027

1028

1029 mutable llvm::raw_null_ostream os;

1030 };

1031 }

1032

1033

1034

1035

1037 StringRef allowedPunctChars = "$._-") {

1038 assert(!name.empty() && "Shouldn't have an empty name here");

1039

1040 auto validChar = [&](char ch) {

1041 return llvm::isAlnum(ch) || allowedPunctChars.contains(ch);

1042 };

1043

1044 auto copyNameToBuffer = [&] {

1045 for (char ch : name) {

1046 if (validChar(ch))

1047 buffer.push_back(ch);

1048 else if (ch == ' ')

1049 buffer.push_back('_');

1050 else

1051 buffer.append(llvm::utohexstr((unsigned char)ch));

1052 }

1053 };

1054

1055

1056

1057

1058 if (isdigit(name[0]) || (!validChar(name[0]) && name[0] != ' ')) {

1059 buffer.push_back('_');

1060 copyNameToBuffer();

1061 return buffer;

1062 }

1063

1064

1065 for (char ch : name) {

1066 if (!validChar(ch)) {

1067 copyNameToBuffer();

1068 return buffer;

1069 }

1070 }

1071

1072

1073 return name;

1074 }

1075

1076 unsigned AliasInitializer::uniqueAliasNameIndex(

1077 StringRef alias, llvm::StringMap &nameCounts,

1079 if (!usedAliases.count(alias)) {

1080 usedAliases.insert(alias);

1081

1082 return 0;

1083 }

1084

1086

1087 if (isdigit(alias.back()))

1088 probeAlias.push_back('_');

1089

1090 if (nameCounts[probeAlias] == 0)

1091 nameCounts[probeAlias] = 1;

1092

1093

1094 while (true) {

1095 unsigned nameIndex = nameCounts[probeAlias]++;

1096 probeAlias += llvm::utostr(nameIndex);

1097 if (!usedAliases.count(probeAlias)) {

1098 usedAliases.insert(probeAlias);

1099 return nameIndex;

1100 }

1101

1102 probeAlias.resize(alias.size() + isdigit(alias.back()) ? 1 : 0);

1103 }

1104 }

1105

1106

1107

1108 void AliasInitializer::initializeAliases(

1109 llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,

1110 llvm::MapVector<const void *, SymbolAlias> &symbolToAlias) {

1112 unprocessedAliases = visitedSymbols.takeVector();

1113 llvm::stable_sort(unprocessedAliases, llvm::less_second());

1114

1115

1116

1117 llvm::BumpPtrAllocator usedAliasAllocator;

1119

1120 llvm::StringMap nameCounts;

1121 for (auto &[symbol, aliasInfo] : unprocessedAliases) {

1122 if (!aliasInfo.alias)

1123 continue;

1124 StringRef alias = *aliasInfo.alias;

1125 unsigned nameIndex = uniqueAliasNameIndex(alias, nameCounts, usedAliases);

1126 symbolToAlias.insert(

1127 {symbol, SymbolAlias(alias, nameIndex, aliasInfo.isType,

1128 aliasInfo.canBeDeferred)});

1129 }

1130 }

1131

1132 void AliasInitializer::initialize(

1134 llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias) {

1135

1136

1137

1138 DummyAliasOperationPrinter aliasPrinter(printerFlags, *this);

1139 aliasPrinter.printCustomOrGenericOp(op);

1140

1141

1142 initializeAliases(aliases, attrTypeToAlias);

1143 }

1144

1145 template <typename T, typename... PrintArgs>

1146 std::pair<size_t, size_t> AliasInitializer::visitImpl(

1147 T value, llvm::MapVector<const void *, InProgressAliasInfo> &aliases,

1148 bool canBeDeferred, PrintArgs &&...printArgs) {

1149 auto [it, inserted] = aliases.try_emplace(value.getAsOpaquePointer());

1150 size_t aliasIndex = std::distance(aliases.begin(), it);

1151 if (!inserted) {

1152

1153 if (!canBeDeferred)

1154 markAliasNonDeferrable(aliasIndex);

1155 return {static_cast<size_t>(it->second.aliasDepth), aliasIndex};

1156 }

1157

1158

1159 generateAlias(value, it->second, canBeDeferred);

1160 it->second.isType = std::is_base_of_v<Type, T>;

1161 it->second.canBeDeferred = canBeDeferred;

1162

1163

1165 DummyAliasDialectAsmPrinter printer(*this, canBeDeferred, childAliases);

1166 size_t maxAliasDepth =

1167 printer.printAndVisitNestedAliases(value, printArgs...);

1168

1169

1170 it = std::next(aliases.begin(), aliasIndex);

1171

1172

1173 it->second.childIndices = std::move(childAliases);

1174 if (maxAliasDepth)

1175 it->second.aliasDepth = maxAliasDepth + 1;

1176

1177

1178 return {(size_t)it->second.aliasDepth, aliasIndex};

1179 }

1180

1181 void AliasInitializer::markAliasNonDeferrable(size_t aliasIndex) {

1182 auto *it = std::next(aliases.begin(), aliasIndex);

1183

1184

1185

1186 if (!it->second.canBeDeferred)

1187 return;

1188

1189 it->second.canBeDeferred = false;

1190

1191

1192 for (size_t childIndex : it->second.childIndices)

1193 markAliasNonDeferrable(childIndex);

1194 }

1195

1196 template

1197 void AliasInitializer::generateAlias(T symbol, InProgressAliasInfo &alias,

1198 bool canBeDeferred) {

1200

1203 using InterfaceT = std::conditional_t<std::is_base_of_v<Attribute, T>,

1204 OpAsmAttrInterface, OpAsmTypeInterface>;

1205 if (auto symbolInterface = dyn_cast(symbol)) {

1206 symbolInterfaceResult = symbolInterface.getAlias(aliasOS);

1208 nameBuffer = std::move(aliasBuffer);

1209 assert(!nameBuffer.empty() && "expected valid alias name");

1210 }

1211 }

1212

1213 if (symbolInterfaceResult != OpAsmDialectInterface::AliasResult::FinalAlias) {

1214 for (const auto &interface : interfaces) {

1216 interface.getAlias(symbol, aliasOS);

1218 continue;

1219 nameBuffer = std::move(aliasBuffer);

1220 assert(!nameBuffer.empty() && "expected valid alias name");

1221 if (result == OpAsmDialectInterface::AliasResult::FinalAlias)

1222 break;

1223 }

1224 }

1225

1226 if (nameBuffer.empty())

1227 return;

1228

1230 StringRef name =

1231 sanitizeIdentifier(nameBuffer, tempBuffer, "$_-");

1232 name = name.copy(aliasAllocator);

1233 alias = InProgressAliasInfo(name);

1234 }

1235

1236

1237

1238

1239

1240 namespace {

1241

1242 class AliasState {

1243 public:

1244

1245 void

1248

1249

1250

1251 LogicalResult getAlias(Attribute attr, raw_ostream &os) const;

1252

1253

1254

1255 LogicalResult getAlias(Type ty, raw_ostream &os) const;

1256

1257

1258

1259 void printNonDeferredAliases(AsmPrinter::Impl &p, NewLineCounter &newLine) {

1260 printAliases(p, newLine, false);

1261 }

1262

1263

1264 void printDeferredAliases(AsmPrinter::Impl &p, NewLineCounter &newLine) {

1265 printAliases(p, newLine, true);

1266 }

1267

1268 private:

1269

1270

1271 void printAliases(AsmPrinter::Impl &p, NewLineCounter &newLine,

1272 bool isDeferred);

1273

1274

1275 llvm::MapVector<const void *, SymbolAlias> attrTypeToAlias;

1276

1277

1278 llvm::BumpPtrAllocator aliasAllocator;

1279 };

1280 }

1281

1282 void AliasState::initialize(

1285 AliasInitializer initializer(interfaces, aliasAllocator);

1286 initializer.initialize(op, printerFlags, attrTypeToAlias);

1287 }

1288

1289 LogicalResult AliasState::getAlias(Attribute attr, raw_ostream &os) const {

1291 if (it == attrTypeToAlias.end())

1292 return failure();

1293 it->second.print(os);

1294 return success();

1295 }

1296

1297 LogicalResult AliasState::getAlias(Type ty, raw_ostream &os) const {

1299 if (it == attrTypeToAlias.end())

1300 return failure();

1301 if (!it->second.isPrinted)

1302 return failure();

1303

1304 it->second.print(os);

1305 return success();

1306 }

1307

1308 void AliasState::printAliases(AsmPrinter::Impl &p, NewLineCounter &newLine,

1309 bool isDeferred) {

1310 auto filterFn = [=](const auto &aliasIt) {

1311 return aliasIt.second.canBeDeferred() == isDeferred;

1312 };

1313 for (auto &[opaqueSymbol, alias] :

1314 llvm::make_filter_range(attrTypeToAlias, filterFn)) {

1317

1318 if (alias.isTypeAlias()) {

1321 alias.isPrinted = true;

1322 } else {

1323

1327 else

1329 }

1330

1332 }

1333 }

1334

1335

1336

1337

1338

1339 namespace {

1340

1341

1342 struct BlockInfo {

1343 int ordering;

1344 StringRef name;

1345 };

1346

1347

1348 class SSANameState {

1349 public:

1350

1351 enum : unsigned { NameSentinel = ~0U };

1352

1354 SSANameState() = default;

1355

1356

1357

1358

1359 void printValueID(Value value, bool printResultNo, raw_ostream &stream) const;

1360

1361

1362 void printOperationID(Operation *op, raw_ostream &stream) const;

1363

1364

1365

1367

1368

1369 BlockInfo getBlockInfo(Block *block);

1370

1371

1372

1373

1374 void shadowRegionArgs(Region &region, ValueRange namesToUse);

1375

1376 private:

1377

1378 void numberValuesInRegion(Region &region);

1379 void numberValuesInBlock(Block &block);

1380 void numberValuesInOp(Operation &op);

1381

1382

1383

1384

1385

1386 void getResultIDAndNumber(OpResult result, Value &lookupValue,

1387 std::optional &lookupResultNo) const;

1388

1389

1390 void setValueName(Value value, StringRef name);

1391

1392

1393

1394 StringRef uniqueValueName(StringRef name);

1395

1396

1397

1400

1401

1402

1404

1405

1406

1407

1409

1410

1411

1413

1414

1415

1416

1417 llvm::ScopedHashTable<StringRef, char> usedNames;

1418 llvm::BumpPtrAllocator usedNameAllocator;

1419

1420

1421 unsigned nextValueID = 0;

1422

1423 unsigned nextArgumentID = 0;

1424

1425 unsigned nextConflictID = 0;

1426

1427

1428

1430 };

1431 }

1432

1434 : printerFlags(printerFlags) {

1435 llvm::SaveAndRestore valueIDSaver(nextValueID);

1436 llvm::SaveAndRestore argumentIDSaver(nextArgumentID);

1437 llvm::SaveAndRestore conflictIDSaver(nextConflictID);

1438

1439

1440

1441

1442 using UsedNamesScopeTy = llvm::ScopedHashTable<StringRef, char>::ScopeTy;

1443 using NamingContext =

1444 std::tuple<Region *, unsigned, unsigned, unsigned, UsedNamesScopeTy *>;

1445

1446

1447 llvm::BumpPtrAllocator allocator;

1448

1449

1450 auto *topLevelNamesScope =

1451 new (allocator.Allocate()) UsedNamesScopeTy(usedNames);

1452

1455 nameContext.push_back(std::make_tuple(&region, nextValueID, nextArgumentID,

1456 nextConflictID, topLevelNamesScope));

1457

1458 numberValuesInOp(*op);

1459

1460 while (!nameContext.empty()) {

1462 UsedNamesScopeTy *parentScope;

1463

1465

1466 std::tie(region, std::ignore, std::ignore, std::ignore, parentScope) =

1467 nameContext.pop_back_val();

1468 else

1469 std::tie(region, nextValueID, nextArgumentID, nextConflictID,

1470 parentScope) = nameContext.pop_back_val();

1471

1472

1473

1474 while (usedNames.getCurScope() != parentScope) {

1475 usedNames.getCurScope()->~UsedNamesScopeTy();

1476 assert((usedNames.getCurScope() != nullptr || parentScope == nullptr) &&

1477 "top level parentScope must be a nullptr");

1478 }

1479

1480

1481 auto *curNamesScope = new (allocator.Allocate())

1482 UsedNamesScopeTy(usedNames);

1483

1484 numberValuesInRegion(*region);

1485

1488 nameContext.push_back(std::make_tuple(&region, nextValueID,

1489 nextArgumentID, nextConflictID,

1490 curNamesScope));

1491 }

1492

1493

1494 while (usedNames.getCurScope() != nullptr)

1495 usedNames.getCurScope()->~UsedNamesScopeTy();

1496 }

1497

1498 void SSANameState::printValueID(Value value, bool printResultNo,

1499 raw_ostream &stream) const {

1500 if (!value) {

1501 stream << "<>";

1502 return;

1503 }

1504

1505 std::optional resultNo;

1506 auto lookupValue = value;

1507

1508

1509

1510 if (OpResult result = dyn_cast(value))

1511 getResultIDAndNumber(result, lookupValue, resultNo);

1512

1513 auto it = valueIDs.find(lookupValue);

1514 if (it == valueIDs.end()) {

1515 stream << "<>";

1516 return;

1517 }

1518

1519 stream << '%';

1520 if (it->second != NameSentinel) {

1521 stream << it->second;

1522 } else {

1523 auto nameIt = valueNames.find(lookupValue);

1524 assert(nameIt != valueNames.end() && "Didn't have a name entry?");

1525 stream << nameIt->second;

1526 }

1527

1528 if (resultNo && printResultNo)

1529 stream << '#' << *resultNo;

1530 }

1531

1532 void SSANameState::printOperationID(Operation *op, raw_ostream &stream) const {

1533 auto it = operationIDs.find(op);

1534 if (it == operationIDs.end()) {

1535 stream << "<>";

1536 } else {

1537 stream << '%' << it->second;

1538 }

1539 }

1540

1542 auto it = opResultGroups.find(op);

1543 return it == opResultGroups.end() ? ArrayRef() : it->second;

1544 }

1545

1546 BlockInfo SSANameState::getBlockInfo(Block *block) {

1547 auto it = blockNames.find(block);

1548 BlockInfo invalidBlock{-1, "INVALIDBLOCK"};

1549 return it != blockNames.end() ? it->second : invalidBlock;

1550 }

1551

1552 void SSANameState::shadowRegionArgs(Region &region, ValueRange namesToUse) {

1553 assert(!region.empty() && "cannot shadow arguments of an empty region");

1555 "incorrect number of names passed in");

1557 "only KnownIsolatedFromAbove ops can shadow names");

1558

1560 for (unsigned i = 0, e = namesToUse.size(); i != e; ++i) {

1561 auto nameToUse = namesToUse[i];

1562 if (nameToUse == nullptr)

1563 continue;

1564 auto nameToReplace = region.getArgument(i);

1565

1566 nameStr.clear();

1567 llvm::raw_svector_ostream nameStream(nameStr);

1568 printValueID(nameToUse, true, nameStream);

1569

1570

1571 assert(valueIDs[nameToReplace] == NameSentinel);

1572

1573

1574 auto name = StringRef(nameStream.str()).drop_front();

1575

1576

1577 valueNames[nameToReplace] = name.copy(usedNameAllocator);

1578 }

1579 }

1580

1581 namespace {

1582

1583 StringRef maybeGetValueNameFromLoc(Value value, StringRef name) {

1585 return maybeNameLoc.getName();

1586 return name;

1587 }

1588 }

1589

1590 void SSANameState::numberValuesInRegion(Region &region) {

1591

1592 bool opAsmOpInterfaceUsed = false;

1593 auto setBlockArgNameFn = [&](Value arg, StringRef name) {

1594 assert(!valueIDs.count(arg) && "arg numbered multiple times");

1595 assert(llvm::cast(arg).getOwner()->getParent() == &region &&

1596 "arg not defined in current region");

1597 opAsmOpInterfaceUsed = true;

1599 name = maybeGetValueNameFromLoc(arg, name);

1600 setValueName(arg, name);

1601 };

1602

1605 if (auto asmInterface = dyn_cast(op))

1606 asmInterface.getAsmBlockArgumentNames(region, setBlockArgNameFn);

1607

1608 if (!opAsmOpInterfaceUsed) {

1610 if (auto interface = dyn_cast(arg.getType())) {

1611 interface.getAsmName(

1612 [&](StringRef name) { setBlockArgNameFn(arg, name); });

1613 }

1614 }

1615 }

1616 }

1617 }

1618

1619

1620 unsigned nextBlockID = 0;

1621 for (auto &block : region) {

1622

1623

1624 auto blockInfoIt = blockNames.insert({&block, {-1, ""}});

1625 if (blockInfoIt.second) {

1626

1627

1628 std::string name;

1629 llvm::raw_string_ostream(name) << "^bb" << nextBlockID;

1630 blockInfoIt.first->second.name = StringRef(name).copy(usedNameAllocator);

1631 }

1632 blockInfoIt.first->second.ordering = nextBlockID++;

1633

1634 numberValuesInBlock(block);

1635 }

1636 }

1637

1638 void SSANameState::numberValuesInBlock(Block &block) {

1639

1640

1642 SmallString<32> specialNameBuffer(isEntryBlock ? "arg" : "");

1643 llvm::raw_svector_ostream specialName(specialNameBuffer);

1645 if (valueIDs.count(arg))

1646 continue;

1647 if (isEntryBlock) {

1648 specialNameBuffer.resize(strlen("arg"));

1649 specialName << nextArgumentID++;

1650 }

1651 StringRef specialNameStr = specialName.str();

1653 specialNameStr = maybeGetValueNameFromLoc(arg, specialNameStr);

1654 setValueName(arg, specialNameStr);

1655 }

1656

1657

1658 for (auto &op : block)

1659 numberValuesInOp(op);

1660 }

1661

1662 void SSANameState::numberValuesInOp(Operation &op) {

1663

1665

1666 bool opAsmOpInterfaceUsed = false;

1667 auto setResultNameFn = [&](Value result, StringRef name) {

1668 assert(!valueIDs.count(result) && "result numbered multiple times");

1669 assert(result.getDefiningOp() == &op && "result not defined by 'op'");

1670 opAsmOpInterfaceUsed = true;

1672 name = maybeGetValueNameFromLoc(result, name);

1673 setValueName(result, name);

1674

1675

1676 if (int resultNo = llvm::cast(result).getResultNumber())

1677 resultGroups.push_back(resultNo);

1678 };

1679

1680 auto setBlockNameFn = [&](Block *block, StringRef name) {

1682 "getAsmBlockArgumentNames callback invoked on a block not directly "

1683 "nested under the current operation");

1684 assert(!blockNames.count(block) && "block numbered multiple times");

1687 if (name.data() != tmpBuffer.data()) {

1688 tmpBuffer.append(name);

1689 name = tmpBuffer.str();

1690 }

1691 name = name.copy(usedNameAllocator);

1692 blockNames[block] = {-1, name};

1693 };

1694

1696 if (OpAsmOpInterface asmInterface = dyn_cast(&op)) {

1697 asmInterface.getAsmBlockNames(setBlockNameFn);

1698 asmInterface.getAsmResultNames(setResultNameFn);

1699 }

1700 if (!opAsmOpInterfaceUsed) {

1701

1702

1703 bool allHaveOpAsmTypeInterface =

1705 return isa(type);

1706 });

1707 if (allHaveOpAsmTypeInterface) {

1709 auto interface = cast(result.getType());

1710 interface.getAsmName(

1711 [&](StringRef name) { setResultNameFn(result, name); });

1712 }

1713 }

1714 }

1715 }

1716

1718 if (numResults == 0) {

1719

1721 if (operationIDs.try_emplace(&op, nextValueID).second)

1722 ++nextValueID;

1723 }

1724 return;

1725 }

1727

1730 setValueName(resultBegin, nameLoc.getName());

1731 }

1732 }

1733

1734

1735 if (valueIDs.try_emplace(resultBegin, nextValueID).second)

1736 ++nextValueID;

1737

1738

1739 if (resultGroups.size() != 1) {

1740 llvm::array_pod_sort(resultGroups.begin(), resultGroups.end());

1741 opResultGroups.try_emplace(&op, std::move(resultGroups));

1742 }

1743 }

1744

1745 void SSANameState::getResultIDAndNumber(

1747 std::optional &lookupResultNo) const {

1750 return;

1752

1753

1754

1755 auto resultGroupIt = opResultGroups.find(owner);

1756 if (resultGroupIt == opResultGroups.end()) {

1757

1758 lookupResultNo = resultNo;

1759 lookupValue = owner->getResult(0);

1760 return;

1761 }

1762

1763

1764 ArrayRef resultGroups = resultGroupIt->second;

1765 const auto *it = llvm::upper_bound(resultGroups, resultNo);

1766 int groupResultNo = 0, groupSize = 0;

1767

1768

1769 if (it == resultGroups.end()) {

1770 groupResultNo = resultGroups.back();

1771 groupSize = static_cast<int>(owner->getNumResults()) - resultGroups.back();

1772 } else {

1773

1774 groupResultNo = *std::prev(it);

1775 groupSize = *it - groupResultNo;

1776 }

1777

1778

1779 if (groupSize != 1)

1780 lookupResultNo = resultNo - groupResultNo;

1781 lookupValue = owner->getResult(groupResultNo);

1782 }

1783

1784 void SSANameState::setValueName(Value value, StringRef name) {

1785

1786 if (name.empty()) {

1787 valueIDs[value] = nextValueID++;

1788 return;

1789 }

1790

1791 valueIDs[value] = NameSentinel;

1792 valueNames[value] = uniqueValueName(name);

1793 }

1794

1795 StringRef SSANameState::uniqueValueName(StringRef name) {

1798

1799

1800 if (!usedNames.count(name)) {

1801 name = name.copy(usedNameAllocator);

1802 } else {

1803

1804

1805

1807 probeName.push_back('_');

1808 while (true) {

1809 probeName += llvm::utostr(nextConflictID++);

1810 if (!usedNames.count(probeName)) {

1811 name = probeName.str().copy(usedNameAllocator);

1812 break;

1813 }

1814 probeName.resize(name.size() + 1);

1815 }

1816 }

1817

1818 usedNames.insert(name, char());

1819 return name;

1820 }

1821

1822

1823

1824

1825

1826 namespace {

1827

1828 class DistinctState {

1829 public:

1830

1832

1833 private:

1834 uint64_t distinctCounter = 0;

1836 };

1837 }

1838

1839 uint64_t DistinctState::getId(DistinctAttr distinctAttr) {

1840 auto [it, inserted] =

1841 distinctAttrMap.try_emplace(distinctAttr, distinctCounter);

1842 if (inserted)

1843 distinctCounter++;

1844 return it->getSecond();

1845 }

1846

1847

1848

1849

1850

1851 AsmParsedResourceEntry::~AsmParsedResourceEntry() = default;

1852 AsmResourceBuilder::~AsmResourceBuilder() = default;

1853 AsmResourceParser::~AsmResourceParser() = default;

1854 AsmResourcePrinter::~AsmResourcePrinter() = default;

1855

1857 switch (kind) {

1858 case AsmResourceEntryKind::Blob:

1859 return "blob";

1860 case AsmResourceEntryKind::Bool:

1861 return "bool";

1862 case AsmResourceEntryKind::String:

1863 return "string";

1864 }

1865 llvm_unreachable("unknown AsmResourceEntryKind");

1866 }

1867

1869 std::unique_ptr &collection = keyToResources[key.str()];

1870 if (!collection)

1871 collection = std::make_unique(key);

1872 return *collection;

1873 }

1874

1875 std::vector<std::unique_ptr>

1877 std::vector<std::unique_ptr> printers;

1878 for (auto &it : keyToResources) {

1879 ResourceCollection *collection = it.second.get();

1881 return collection->buildResources(op, builder);

1882 };

1883 printers.emplace_back(

1885 }

1886 return printers;

1887 }

1888

1889 LogicalResult FallbackAsmResourceMap::ResourceCollection::parseResource(

1891 switch (entry.getKind()) {

1893 FailureOr blob = entry.parseAsBlob();

1894 if (failed(blob))

1895 return failure();

1896 resources.emplace_back(entry.getKey(), std::move(*blob));

1897 return success();

1898 }

1900 FailureOr value = entry.parseAsBool();

1901 if (failed(value))

1902 return failure();

1903 resources.emplace_back(entry.getKey(), *value);

1904 break;

1905 }

1907 FailureOrstd::string str = entry.parseAsString();

1908 if (failed(str))

1909 return failure();

1910 resources.emplace_back(entry.getKey(), std::move(*str));

1911 break;

1912 }

1913 }

1914 return success();

1915 }

1916

1917 void FallbackAsmResourceMap::ResourceCollection::buildResources(

1919 for (const auto &entry : resources) {

1920 if (const auto *value = std::get_if(&entry.value))

1921 builder.buildBlob(entry.key, *value);

1922 else if (const auto *value = std::get_if(&entry.value))

1923 builder.buildBool(entry.key, *value);

1924 else if (const auto *value = std::get_ifstd::string(&entry.value))

1926 else

1927 llvm_unreachable("unknown AsmResourceEntryKind");

1928 }

1929 }

1930

1931

1932

1933

1934

1935 namespace mlir {

1936 namespace detail {

1938 public:

1941 : interfaces(op->getContext()), nameState(op, printerFlags),

1942 printerFlags(printerFlags), locationMap(locationMap) {}

1945 : interfaces(ctx), printerFlags(printerFlags), locationMap(locationMap) {}

1946

1947

1949 aliasState.initialize(op, printerFlags, interfaces);

1950 }

1951

1952

1954

1955

1957

1958

1960

1961

1962

1964 return interfaces;

1965 }

1966

1967

1969 return llvm::make_pointee_range(externalResourcePrinters);

1970 }

1971

1972

1974

1975

1976

1978 if (locationMap)

1979 (*locationMap)[op] = std::make_pair(line, col);

1980 }

1981

1982

1985 return dialectResources;

1986 }

1987

1989 return success(cyclicPrintingStack.insert(opaquePointer));

1990 }

1991

1993

1994 private:

1995

1997

1998

2000

2001

2003

2004

2005 AliasState aliasState;

2006

2007

2008 SSANameState nameState;

2009

2010

2011 DistinctState distinctState;

2012

2013

2015

2016

2018

2019

2020

2022

2023

2025 };

2026

2027 template

2029 llvm::interleave(

2030 shape, stream,

2031 [&stream](const auto &dimSize) {

2032 if (ShapedType::isDynamic(dimSize))

2033 stream << "?";

2034 else

2035 stream << dimSize;

2036 },

2037 "x");

2038 }

2039

2040 }

2041 }

2042

2043

2044

2045

2050 return printerFlags;

2051

2052

2053

2054 auto parentThreadId = llvm::get_threadid();

2056 if (parentThreadId == llvm::get_threadid()) {

2057 LLVM_DEBUG({

2058 diag.print(llvm::dbgs());

2059 llvm::dbgs() << "\n";

2060 });

2061 return success();

2062 }

2063 return failure();

2064 });

2065 if (failed(verify(op))) {

2066 LLVM_DEBUG(llvm::dbgs()

2068 << "' failed to verify and will be printed in generic form\n");

2070 }

2071

2072 return printerFlags;

2073 }

2074

2079 if (map)

2081 }

2084 : impl(std::make_unique<AsmStateImpl>(ctx, printerFlags, locationMap)) {

2085 if (map)

2087 }

2089

2091 return impl->getPrinterFlags();

2092 }

2093

2095 std::unique_ptr printer) {

2096 impl->externalResourcePrinters.emplace_back(std::move(printer));

2097 }

2098

2101 return impl->getDialectResources();

2102 }

2103

2104

2105

2106

2107

2109 : os(os), state(state), printerFlags(state.getPrinterFlags()) {}

2110

2112

2114 return;

2115

2116 os << " ";

2117 printLocation(loc, allowAlias);

2118 }

2119

2121 bool isTopLevel) {

2122

2123 if (!isTopLevel && succeeded(state.getAliasState().getAlias(loc, os)))

2124 return;

2125

2127 .Case([&](OpaqueLoc loc) {

2128 printLocationInternal(loc.getFallbackLocation(), pretty);

2129 })

2130 .Case([&](UnknownLoc loc) {

2131 if (pretty)

2132 os << "[unknown]";

2133 else

2134 os << "unknown";

2135 })

2137 if (pretty)

2138 os << loc.getFilename().getValue();

2139 else

2140 printEscapedString(loc.getFilename());

2141 if (loc.getEndColumn() == loc.getStartColumn() &&

2142 loc.getStartLine() == loc.getEndLine()) {

2143 os << ':' << loc.getStartLine() << ':' << loc.getStartColumn();

2144 return;

2145 }

2146 if (loc.getStartLine() == loc.getEndLine()) {

2147 os << ':' << loc.getStartLine() << ':' << loc.getStartColumn()

2148 << " to :" << loc.getEndColumn();

2149 return;

2150 }

2151 os << ':' << loc.getStartLine() << ':' << loc.getStartColumn() << " to "

2152 << loc.getEndLine() << ':' << loc.getEndColumn();

2153 })

2154 .Case([&](NameLoc loc) {

2155 printEscapedString(loc.getName());

2156

2157

2158 auto childLoc = loc.getChildLoc();

2159 if (!llvm::isa(childLoc)) {

2160 os << '(';

2161 printLocationInternal(childLoc, pretty);

2162 os << ')';

2163 }

2164 })

2165 .Case([&](CallSiteLoc loc) {

2166 Location caller = loc.getCaller();

2167 Location callee = loc.getCallee();

2168 if (!pretty)

2169 os << "callsite(";

2170 printLocationInternal(callee, pretty);

2171 if (pretty) {

2172 if (llvm::isa(callee)) {

2173 if (llvm::isa(caller)) {

2174 os << " at ";

2175 } else {

2176 os << newLine << " at ";

2177 }

2178 } else {

2179 os << newLine << " at ";

2180 }

2181 } else {

2182 os << " at ";

2183 }

2184 printLocationInternal(caller, pretty);

2185 if (!pretty)

2186 os << ")";

2187 })

2188 .Case([&](FusedLoc loc) {

2189 if (!pretty)

2190 os << "fused";

2191 if (Attribute metadata = loc.getMetadata()) {

2192 os << '<';

2194 os << '>';

2195 }

2196 os << '[';

2197 interleave(

2198 loc.getLocations(),

2199 [&](Location loc) { printLocationInternal(loc, pretty); },

2200 [&]() { os << ", "; });

2201 os << ']';

2202 })

2203 .Default([&](LocationAttr loc) {

2204 // Assumes that this is a dialect-specific attribute and prints it

2205 // directly.

2206 printAttribute(loc);

2207 });

2208 }

2209

2210

2211

2212 static void printFloatValue(const APFloat &apValue, raw_ostream &os,

2213 bool *printedHex = nullptr) {

2214 // We would like to output the FP constant value in exponential notation,

2215 // but we cannot do this if doing so will lose precision. Check here to

2216 // make sure that we only output it in exponential format if we can parse

2217 // the value back and get the same value.

2218 bool isInf = apValue.isInfinity();

2219 bool isNaN = apValue.isNaN();

2220 if (!isInf && !isNaN) {

2221 SmallString<128> strValue;

2222 apValue.toString(strValue, /*FormatPrecision=*/6, /*FormatMaxPadding=*/0,

2223 /*TruncateZero=*/false);

2224

2225 // Check to make sure that the stringized number is not some string like

2226 // "Inf" or NaN, that atof will accept, but the lexer will not. Check

2227 // that the string matches the "[-+]?[0-9]" regex.

2228 assert(((strValue[0] >= '0' && strValue[0] <= '9') ||

2229 ((strValue[0] == '-' || strValue[0] == '+') &&

2230 (strValue[1] >= '0' && strValue[1] <= '9'))) &&

2231 "[-+]?[0-9] regex does not match!");

2232

2233

2234

2235 if (APFloat(apValue.getSemantics(), strValue).bitwiseIsEqual(apValue)) {

2236 os << strValue;

2237 return;

2238 }

2239

2240

2241

2242 strValue.clear();

2243 apValue.toString(strValue);

2244

2245

2246 if (strValue.str().contains('.')) {

2247 os << strValue;

2248 return;

2249 }

2250 }

2251

2252

2253

2254 if (printedHex)

2255 *printedHex = true;

2257 APInt apInt = apValue.bitcastToAPInt();

2258 apInt.toString(str, 16, false,

2259 true);

2260 os << str;

2261 }

2262

2265 return printLocationInternal(loc, true, true);

2266

2267 os << "loc(";

2268 if (!allowAlias || failed(printAlias(loc)))

2269 printLocationInternal(loc, false, true);

2270 os << ')';

2271 }

2272

2273

2274

2275

2277

2278 if (symName.empty() || !isalpha(symName.front()))

2279 return false;

2280

2281

2282

2283 symName = symName.drop_while(

2284 [](char c) { return llvm::isAlnum(c) || c == '.' || c == '_'; });

2285 if (symName.empty())

2286 return true;

2287

2288

2289

2290 return symName.front() == '<' && symName.back() == '>';

2291 }

2292

2293

2295 StringRef dialectName, StringRef symString) {

2296 os << symPrefix << dialectName;

2297

2298

2299

2301 os << '.' << symString;

2302 return;

2303 }

2304

2305 os << '<' << symString << '>';

2306 }

2307

2308

2309 static bool isBareIdentifier(StringRef name) {

2310 // By making this unsigned, the value passed in to isalnum will always be

2311 // in the range 0-255. This is important when building with MSVC because

2312 // its implementation will assert. This situation can arise when dealing

2313 // with UTF-8 multibyte characters.

2314 if (name.empty() || (!isalpha(name[0]) && name[0] != '_'))

2315 return false;

2316 return llvm::all_of(name.drop_front(), [](unsigned char c) {

2317 return isalnum(c) || c == '_' || c == '$' || c == '.';

2318 });

2319 }

2320

2321

2322

2323 static void printKeywordOrString(StringRef keyword, raw_ostream &os) {

2324 // If it can be represented as a bare identifier, write it directly.

2325 if (isBareIdentifier(keyword)) {

2326 os << keyword;

2327 return;

2328 }

2329

2330 // Otherwise, output the keyword wrapped in quotes with proper escaping.

2331 os << "\"";

2332 printEscapedString(keyword, os);

2333 os << '"';

2334 }

2335

2336

2337

2338

2339 static void printSymbolReference(StringRef symbolRef, raw_ostream &os) {

2340 if (symbolRef.empty()) {

2341 os << "@<>";

2342 return;

2343 }

2344 os << '@';

2345 printKeywordOrString(symbolRef, os);

2346 }

2347

2348 // Print out a valid ElementsAttr that is succinct and can represent any

2349 // potential shape/type, for use when eliding a large ElementsAttr.

2350 //

2351 // We choose to use a dense resource ElementsAttr literal with conspicuous

2352 // content to hopefully alert readers to the fact that this has been elided.

2353 static void printElidedElementsAttr(raw_ostream &os) {

2354 os << R"(dense_resource<__elided__>)";

2355 }

2356

2357 void AsmPrinter::Impl::printResourceHandle(

2358 const AsmDialectResourceHandle &resource) {

2359 auto *interface = cast(resource.getDialect());

2360 ::printKeywordOrString(interface->getResourceKey(resource), os);

2361 state.getDialectResources()[resource.getDialect()].insert(resource);

2362 }

2363

2364 LogicalResult AsmPrinter::Impl::printAlias(Attribute attr) {

2365 return state.getAliasState().getAlias(attr, os);

2366 }

2367

2368 LogicalResult AsmPrinter::Impl::printAlias(Type type) {

2369 return state.getAliasState().getAlias(type, os);

2370 }

2371

2372 void AsmPrinter::Impl::printAttribute(Attribute attr,

2373 AttrTypeElision typeElision) {

2374 if (!attr) {

2375 os << "<>";

2376 return;

2377 }

2378

2379 // Try to print an alias for this attribute.

2380 if (succeeded(printAlias(attr)))

2381 return;

2382 return printAttributeImpl(attr, typeElision);

2383 }

2384

2385 void AsmPrinter::Impl::printAttributeImpl(Attribute attr,

2386 AttrTypeElision typeElision) {

2387 if (!isa(attr.getDialect())) {

2388 printDialectAttribute(attr);

2389 } else if (auto opaqueAttr = llvm::dyn_cast(attr)) {

2390 printDialectSymbol(os, "#", opaqueAttr.getDialectNamespace(),

2391 opaqueAttr.getAttrData());

2392 } else if (llvm::isa(attr)) {

2393 os << "unit";

2394 return;

2395 } else if (auto distinctAttr = llvm::dyn_cast(attr)) {

2396 os << "distinct[" << state.getDistinctState().getId(distinctAttr) << "]<";

2397 if (!llvm::isa(distinctAttr.getReferencedAttr())) {

2398 printAttribute(distinctAttr.getReferencedAttr());

2399 }

2400 os << '>';

2401 return;

2402 } else if (auto dictAttr = llvm::dyn_cast(attr)) {

2403 os << '{';

2404 interleaveComma(dictAttr.getValue(),

2405 [&](NamedAttribute attr) { printNamedAttribute(attr); });

2406 os << '}';

2407

2408 } else if (auto intAttr = llvm::dyn_cast(attr)) {

2409 Type intType = intAttr.getType();

2410 if (intType.isSignlessInteger(1)) {

2411 os << (intAttr.getValue().getBoolValue() ? "true" : "false");

2412

2413 // Boolean integer attributes always elides the type.

2414 return;

2415 }

2416

2417 // Only print attributes as unsigned if they are explicitly unsigned or are

2418 // signless 1-bit values. Indexes, signed values, and multi-bit signless

2419 // values print as signed.

2420 bool isUnsigned =

2421 intType.isUnsignedInteger() || intType.isSignlessInteger(1);

2422 intAttr.getValue().print(os, !isUnsigned);

2423

2424 // IntegerAttr elides the type if I64.

2425 if (typeElision == AttrTypeElision::May && intType.isSignlessInteger(64))

2426 return;

2427

2428 } else if (auto floatAttr = llvm::dyn_cast(attr)) {

2429 bool printedHex = false;

2430 printFloatValue(floatAttr.getValue(), os, &printedHex);

2431

2432 // FloatAttr elides the type if F64.

2433 if (typeElision == AttrTypeElision::May && floatAttr.getType().isF64() &&

2434 !printedHex)

2435 return;

2436

2437 } else if (auto strAttr = llvm::dyn_cast(attr)) {

2438 printEscapedString(strAttr.getValue());

2439

2440 } else if (auto arrayAttr = llvm::dyn_cast(attr)) {

2441 os << '[';

2442 interleaveComma(arrayAttr.getValue(), [&](Attribute attr) {

2443 printAttribute(attr, AttrTypeElision::May);

2444 });

2445 os << ']';

2446

2447 } else if (auto affineMapAttr = llvm::dyn_cast(attr)) {

2448 os << "affine_map<";

2449 affineMapAttr.getValue().print(os);

2450 os << '>';

2451

2452 // AffineMap always elides the type.

2453 return;

2454

2455 } else if (auto integerSetAttr = llvm::dyn_cast(attr)) {

2456 os << "affine_set<";

2457 integerSetAttr.getValue().print(os);

2458 os << '>';

2459

2460 // IntegerSet always elides the type.

2461 return;

2462

2463 } else if (auto typeAttr = llvm::dyn_cast(attr)) {

2464 printType(typeAttr.getValue());

2465

2466 } else if (auto refAttr = llvm::dyn_cast(attr)) {

2467 printSymbolReference(refAttr.getRootReference().getValue(), os);

2468 for (FlatSymbolRefAttr nestedRef : refAttr.getNestedReferences()) {

2469 os << "::";

2470 printSymbolReference(nestedRef.getValue(), os);

2471 }

2472

2473 } else if (auto intOrFpEltAttr =

2474 llvm::dyn_cast(attr)) {

2475 if (printerFlags.shouldElideElementsAttr(intOrFpEltAttr)) {

2476 printElidedElementsAttr(os);

2477 } else {

2478 os << "dense<";

2479 printDenseIntOrFPElementsAttr(intOrFpEltAttr, /*allowHex=*/true);

2480 os << '>';

2481 }

2482

2483 } else if (auto strEltAttr = llvm::dyn_cast(attr)) {

2484 if (printerFlags.shouldElideElementsAttr(strEltAttr)) {

2485 printElidedElementsAttr(os);

2486 } else {

2487 os << "dense<";

2488 printDenseStringElementsAttr(strEltAttr);

2489 os << '>';

2490 }

2491

2492 } else if (auto sparseEltAttr = llvm::dyn_cast(attr)) {

2493 if (printerFlags.shouldElideElementsAttr(sparseEltAttr.getIndices()) ||

2494 printerFlags.shouldElideElementsAttr(sparseEltAttr.getValues())) {

2495 printElidedElementsAttr(os);

2496 } else {

2497 os << "sparse<";

2498 DenseIntElementsAttr indices = sparseEltAttr.getIndices();

2499 if (indices.getNumElements() != 0) {

2500 printDenseIntOrFPElementsAttr(indices, /*allowHex=*/false);

2501 os << ", ";

2502 printDenseElementsAttr(sparseEltAttr.getValues(), /*allowHex=*/true);

2503 }

2504 os << '>';

2505 }

2506 } else if (auto stridedLayoutAttr = llvm::dyn_cast(attr)) {

2507 stridedLayoutAttr.print(os);

2508 } else if (auto denseArrayAttr = llvm::dyn_cast(attr)) {

2509 os << "array<";

2510 printType(denseArrayAttr.getElementType());

2511 if (!denseArrayAttr.empty()) {

2512 os << ": ";

2513 printDenseArrayAttr(denseArrayAttr);

2514 }

2515 os << ">";

2516 return;

2517 } else if (auto resourceAttr =

2518 llvm::dyn_cast(attr)) {

2519 os << "dense_resource<";

2520 printResourceHandle(resourceAttr.getRawHandle());

2521 os << ">";

2522 } else if (auto locAttr = llvm::dyn_cast(attr)) {

2523 printLocation(locAttr);

2524 } else {

2525 llvm::report_fatal_error("Unknown builtin attribute");

2526 }

2527 // Don't print the type if we must elide it, or if it is a None type.

2528 if (typeElision != AttrTypeElision::Must) {

2529 if (auto typedAttr = llvm::dyn_cast(attr)) {

2530 Type attrType = typedAttr.getType();

2531 if (!llvm::isa(attrType)) {

2532 os << " : ";

2533 printType(attrType);

2534 }

2535 }

2536 }

2537 }

2538

2539

2540 static void printDenseIntElement(const APInt &value, raw_ostream &os,

2541 Type type) {

2542 if (type.isInteger(1))

2543 os << (value.getBoolValue() ? "true" : "false");

2544 else

2545 value.print(os, !type.isUnsignedInteger());

2546 }

2547

2548 static void

2549 printDenseElementsAttrImpl(bool isSplat, ShapedType type, raw_ostream &os,

2550 function_ref<void(unsigned)> printEltFn) {

2551 // Special case for 0-d and splat tensors.

2552 if (isSplat)

2553 return printEltFn(0);

2554

2555 // Special case for degenerate tensors.

2556 auto numElements = type.getNumElements();

2557 if (numElements == 0)

2558 return;

2559

2560 // We use a mixed-radix counter to iterate through the shape. When we bump a

2561 // non-least-significant digit, we emit a close bracket. When we next emit an

2562 // element we re-open all closed brackets.

2563

2564 // The mixed-radix counter, with radices in 'shape'.

2565 int64_t rank = type.getRank();

2566 SmallVector<unsigned, 4> counter(rank, 0);

2567 // The number of brackets that have been opened and not closed.

2568 unsigned openBrackets = 0;

2569

2570 auto shape = type.getShape();

2571 auto bumpCounter = [&] {

2572 // Bump the least significant digit.

2573 ++counter[rank - 1];

2574 // Iterate backwards bubbling back the increment.

2575 for (unsigned i = rank - 1; i > 0; --i)

2576 if (counter[i] >= shape[i]) {

2577 // Index 'i' is rolled over. Bump (i-1) and close a bracket.

2578 counter[i] = 0;

2579 ++counter[i - 1];

2580 --openBrackets;

2581 os << ']';

2582 }

2583 };

2584

2585 for (unsigned idx = 0, e = numElements; idx != e; ++idx) {

2586 if (idx != 0)

2587 os << ", ";

2588 while (openBrackets++ < rank)

2589 os << '[';

2590 openBrackets = rank;

2591 printEltFn(idx);

2592 bumpCounter();

2593 }

2594 while (openBrackets-- > 0)

2595 os << ']';

2596 }

2597

2598 void AsmPrinter::Impl::printDenseElementsAttr(DenseElementsAttr attr,

2599 bool allowHex) {

2600 if (auto stringAttr = llvm::dyn_cast(attr))

2601 return printDenseStringElementsAttr(stringAttr);

2602

2603 printDenseIntOrFPElementsAttr(llvm::cast(attr),

2604 allowHex);

2605 }

2606

2607 void AsmPrinter::Impl::printDenseIntOrFPElementsAttr(

2608 DenseIntOrFPElementsAttr attr, bool allowHex) {

2609 auto type = attr.getType();

2610 auto elementType = type.getElementType();

2611

2612 // Check to see if we should format this attribute as a hex string.

2613 if (allowHex && printerFlags.shouldPrintElementsAttrWithHex(attr)) {

2614 ArrayRef rawData = attr.getRawData();

2615 if (llvm::endianness::native == llvm::endianness::big) {

2616 // Convert endianess in big-endian(BE) machines. `rawData` is BE in BE

2617 // machines. It is converted here to print in LE format.

2618 SmallVector<char, 64> outDataVec(rawData.size());

2619 MutableArrayRef convRawData(outDataVec);

2620 DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(

2621 rawData, convRawData, type);

2622 printHexString(convRawData);

2623 } else {

2624 printHexString(rawData);

2625 }

2626

2627 return;

2628 }

2629

2630 if (ComplexType complexTy = llvm::dyn_cast(elementType)) {

2631 Type complexElementType = complexTy.getElementType();

2632 // Note: The if and else below had a common lambda function which invoked

2633 // printDenseElementsAttrImpl. This lambda was hitting a bug in gcc 9.1,9.2

2634 // and hence was replaced.

2635 if (llvm::isa(complexElementType)) {

2636 auto valueIt = attr.value_begin<std::complex>();

2637 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {

2638 auto complexValue = *(valueIt + index);

2639 os << "(";

2640 printDenseIntElement(complexValue.real(), os, complexElementType);

2641 os << ",";

2642 printDenseIntElement(complexValue.imag(), os, complexElementType);

2643 os << ")";

2644 });

2645 } else {

2646 auto valueIt = attr.value_begin<std::complex>();

2647 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {

2648 auto complexValue = *(valueIt + index);

2649 os << "(";

2650 printFloatValue(complexValue.real(), os);

2651 os << ",";

2652 printFloatValue(complexValue.imag(), os);

2653 os << ")";

2654 });

2655 }

2656 } else if (elementType.isIntOrIndex()) {

2657 auto valueIt = attr.value_begin();

2658 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {

2659 printDenseIntElement(*(valueIt + index), os, elementType);

2660 });

2661 } else {

2662 assert(llvm::isa(elementType) && "unexpected element type");

2663 auto valueIt = attr.value_begin();

2664 printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {

2665 printFloatValue(*(valueIt + index), os);

2666 });

2667 }

2668 }

2669

2670 void AsmPrinter::Impl::printDenseStringElementsAttr(

2671 DenseStringElementsAttr attr) {

2672 ArrayRef data = attr.getRawStringData();

2673 auto printFn = [&](unsigned index) { printEscapedString(data[index]); };

2674 printDenseElementsAttrImpl(attr.isSplat(), attr.getType(), os, printFn);

2675 }

2676

2677 void AsmPrinter::Impl::printDenseArrayAttr(DenseArrayAttr attr) {

2678 Type type = attr.getElementType();

2679 unsigned bitwidth = type.isInteger(1) ? 8 : type.getIntOrFloatBitWidth();

2680 unsigned byteSize = bitwidth / 8;

2681 ArrayRef data = attr.getRawData();

2682

2683 auto printElementAt = [&](unsigned i) {

2684 APInt value(bitwidth, 0);

2685 if (bitwidth) {

2686 llvm::LoadIntFromMemory(

2687 value, reinterpret_cast<const uint8_t *>(data.begin() + byteSize * i),

2688 byteSize);

2689 }

2690 // Print the data as-is or as a float.

2691 if (type.isIntOrIndex()) {

2692 printDenseIntElement(value, getStream(), type);

2693 } else {

2694 APFloat fltVal(llvm::cast(type).getFloatSemantics(), value);

2695 printFloatValue(fltVal, getStream());

2696 }

2697 };

2698 llvm::interleaveComma(llvm::seq(0, attr.size()), getStream(),

2699 printElementAt);

2700 }

2701

2702 void AsmPrinter::Impl::printType(Type type) {

2703 if (!type) {

2704 os << "<>";

2705 return;

2706 }

2707

2708 // Try to print an alias for this type.

2709 if (succeeded(printAlias(type)))

2710 return;

2711 return printTypeImpl(type);

2712 }

2713

2714 void AsmPrinter::Impl::printTypeImpl(Type type) {

2715 TypeSwitch(type)

2716 .Case([&](OpaqueType opaqueTy) {

2717 printDialectSymbol(os, "!", opaqueTy.getDialectNamespace(),

2718 opaqueTy.getTypeData());

2719 })

2720 .Case([&](Type) { os << "index"; })

2721 .Case([&](Type) { os << "f4E2M1FN"; })

2722 .Case([&](Type) { os << "f6E2M3FN"; })

2723 .Case([&](Type) { os << "f6E3M2FN"; })

2724 .Case([&](Type) { os << "f8E5M2"; })

2725 .Case([&](Type) { os << "f8E4M3"; })

2726 .Case([&](Type) { os << "f8E4M3FN"; })

2727 .Case([&](Type) { os << "f8E5M2FNUZ"; })

2728 .Case([&](Type) { os << "f8E4M3FNUZ"; })

2729 .Case([&](Type) { os << "f8E4M3B11FNUZ"; })

2730 .Case([&](Type) { os << "f8E3M4"; })

2731 .Case([&](Type) { os << "f8E8M0FNU"; })

2732 .Case([&](Type) { os << "bf16"; })

2733 .Case([&](Type) { os << "f16"; })

2734 .Case([&](Type) { os << "tf32"; })

2735 .Case([&](Type) { os << "f32"; })

2736 .Case([&](Type) { os << "f64"; })

2737 .Case([&](Type) { os << "f80"; })

2738 .Case([&](Type) { os << "f128"; })

2739 .Case([&](IntegerType integerTy) {

2740 if (integerTy.isSigned())

2741 os << 's';

2742 else if (integerTy.isUnsigned())

2743 os << 'u';

2744 os << 'i' << integerTy.getWidth();

2745 })

2746 .Case([&](FunctionType funcTy) {

2747 os << '(';

2748 interleaveComma(funcTy.getInputs(), [&](Type ty) { printType(ty); });

2749 os << ") -> ";

2750 ArrayRef results = funcTy.getResults();

2751 if (results.size() == 1 && !llvm::isa(results[0])) {

2752 printType(results[0]);

2753 } else {

2754 os << '(';

2755 interleaveComma(results, [&](Type ty) { printType(ty); });

2756 os << ')';

2757 }

2758 })

2759 .Case([&](VectorType vectorTy) {

2760 auto scalableDims = vectorTy.getScalableDims();

2761 os << "vector<";

2762 auto vShape = vectorTy.getShape();

2763 unsigned lastDim = vShape.size();

2764 unsigned dimIdx = 0;

2765 for (dimIdx = 0; dimIdx < lastDim; dimIdx++) {

2766 if (!scalableDims.empty() && scalableDims[dimIdx])

2767 os << '[';

2768 os << vShape[dimIdx];

2769 if (!scalableDims.empty() && scalableDims[dimIdx])

2770 os << ']';

2771 os << 'x';

2772 }

2773 printType(vectorTy.getElementType());

2774 os << '>';

2775 })

2776 .Case([&](RankedTensorType tensorTy) {

2777 os << "tensor<";

2778 printDimensionList(tensorTy.getShape());

2779 if (!tensorTy.getShape().empty())

2780 os << 'x';

2781 printType(tensorTy.getElementType());

2782 // Only print the encoding attribute value if set.

2783 if (tensorTy.getEncoding()) {

2784 os << ", ";

2785 printAttribute(tensorTy.getEncoding());

2786 }

2787 os << '>';

2788 })

2789 .Case([&](UnrankedTensorType tensorTy) {

2790 os << "tensor<*x";

2791 printType(tensorTy.getElementType());

2792 os << '>';

2793 })

2794 .Case([&](MemRefType memrefTy) {

2795 os << "memref<";

2796 printDimensionList(memrefTy.getShape());

2797 if (!memrefTy.getShape().empty())

2798 os << 'x';

2799 printType(memrefTy.getElementType());

2800 MemRefLayoutAttrInterface layout = memrefTy.getLayout();

2801 if (!llvm::isa(layout) || !layout.isIdentity()) {

2802 os << ", ";

2803 printAttribute(memrefTy.getLayout(), AttrTypeElision::May);

2804 }

2805 // Only print the memory space if it is the non-default one.

2806 if (memrefTy.getMemorySpace()) {

2807 os << ", ";

2808 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);

2809 }

2810 os << '>';

2811 })

2812 .Case([&](UnrankedMemRefType memrefTy) {

2813 os << "memref<*x";

2814 printType(memrefTy.getElementType());

2815 // Only print the memory space if it is the non-default one.

2816 if (memrefTy.getMemorySpace()) {

2817 os << ", ";

2818 printAttribute(memrefTy.getMemorySpace(), AttrTypeElision::May);

2819 }

2820 os << '>';

2821 })

2822 .Case([&](ComplexType complexTy) {

2823 os << "complex<";

2824 printType(complexTy.getElementType());

2825 os << '>';

2826 })

2827 .Case([&](TupleType tupleTy) {

2828 os << "tuple<";

2829 interleaveComma(tupleTy.getTypes(),

2830 [&](Type type) { printType(type); });

2831 os << '>';

2832 })

2833 .Case([&](Type) { os << "none"; })

2834 .Default([&](Type type) { return printDialectType(type); });

2835 }

2836

2837 void AsmPrinter::Impl::printOptionalAttrDict(ArrayRef attrs,

2838 ArrayRef elidedAttrs,

2839 bool withKeyword) {

2840 // If there are no attributes, then there is nothing to be done.

2841 if (attrs.empty())

2842 return;

2843

2844 // Functor used to print a filtered attribute list.

2845 auto printFilteredAttributesFn = [&](auto filteredAttrs) {

2846 // Print the 'attributes' keyword if necessary.

2847 if (withKeyword)

2848 os << " attributes";

2849

2850 // Otherwise, print them all out in braces.

2851 os << " {";

2852 interleaveComma(filteredAttrs,

2853 [&](NamedAttribute attr) { printNamedAttribute(attr); });

2854 os << '}';

2855 };

2856

2857 // If no attributes are elided, we can directly print with no filtering.

2858 if (elidedAttrs.empty())

2859 return printFilteredAttributesFn(attrs);

2860

2861 // Otherwise, filter out any attributes that shouldn't be included.

2862 llvm::SmallDenseSet elidedAttrsSet(elidedAttrs.begin(),

2863 elidedAttrs.end());

2864 auto filteredAttrs = llvm::make_filter_range(attrs, [&](NamedAttribute attr) {

2865 return !elidedAttrsSet.contains(attr.getName().strref());

2866 });

2867 if (!filteredAttrs.empty())

2868 printFilteredAttributesFn(filteredAttrs);

2869 }

2870 void AsmPrinter::Impl::printNamedAttribute(NamedAttribute attr) {

2871 // Print the name without quotes if possible.

2872 ::printKeywordOrString(attr.getName().strref(), os);

2873

2874 // Pretty printing elides the attribute value for unit attributes.

2875 if (llvm::isa(attr.getValue()))

2876 return;

2877

2878 os << " = ";

2879 printAttribute(attr.getValue());

2880 }

2881

2882 void AsmPrinter::Impl::printDialectAttribute(Attribute attr) {

2883 auto &dialect = attr.getDialect();

2884

2885 // Ask the dialect to serialize the attribute to a string.

2886 std::string attrName;

2887 {

2888 llvm::raw_string_ostream attrNameStr(attrName);

2889 Impl subPrinter(attrNameStr, state);

2890 DialectAsmPrinter printer(subPrinter);

2891 dialect.printAttribute(attr, printer);

2892 }

2893 printDialectSymbol(os, "#", dialect.getNamespace(), attrName);

2894 }

2895

2896 void AsmPrinter::Impl::printDialectType(Type type) {

2897 auto &dialect = type.getDialect();

2898

2899 // Ask the dialect to serialize the type to a string.

2900 std::string typeName;

2901 {

2902 llvm::raw_string_ostream typeNameStr(typeName);

2903 Impl subPrinter(typeNameStr, state);

2904 DialectAsmPrinter printer(subPrinter);

2905 dialect.printType(type, printer);

2906 }

2907 printDialectSymbol(os, "!", dialect.getNamespace(), typeName);

2908 }

2909

2910 void AsmPrinter::Impl::printEscapedString(StringRef str) {

2911 os << "\"";

2912 llvm::printEscapedString(str, os);

2913 os << "\"";

2914 }

2915

2917 os << "\"0x" << llvm::toHex(str) << "\"";

2918 }

2920 printHexString(StringRef(data.data(), data.size()));

2921 }

2922

2924 return state.pushCyclicPrinting(opaquePointer);

2925 }

2926

2928

2931 }

2932

2933

2934

2935

2936

2938

2940 assert(impl && "expected AsmPrinter::getStream to be overriden");

2941 return impl->getStream();

2942 }

2943

2944

2946 assert(impl && "expected AsmPrinter::printFloat to be overriden");

2948 }

2949

2951 assert(impl && "expected AsmPrinter::printType to be overriden");

2952 impl->printType(type);

2953 }

2954

2956 assert(impl && "expected AsmPrinter::printAttribute to be overriden");

2957 impl->printAttribute(attr);

2958 }

2959

2961 assert(impl && "expected AsmPrinter::printAlias to be overriden");

2962 return impl->printAlias(attr);

2963 }

2964

2966 assert(impl && "expected AsmPrinter::printAlias to be overriden");

2967 return impl->printAlias(type);

2968 }

2969

2971 assert(impl &&

2972 "expected AsmPrinter::printAttributeWithoutType to be overriden");

2974 }

2975

2977 assert(impl && "expected AsmPrinter::printKeywordOrString to be overriden");

2979 }

2980

2982 assert(impl && "expected AsmPrinter::printString to be overriden");

2983 *this << '"';

2984 printEscapedString(keyword, getStream());

2985 *this << '"';

2986 }

2987

2989 assert(impl && "expected AsmPrinter::printSymbolName to be overriden");

2991 }

2992

2994 assert(impl && "expected AsmPrinter::printResourceHandle to be overriden");

2995 impl->printResourceHandle(resource);

2996 }

2997

3000 }

3001

3003 return impl->pushCyclicPrinting(opaquePointer);

3004 }

3005

3007

3008

3009

3010

3011

3014 printAffineExprInternal(expr, BindingStrength::Weak, printValueName);

3015 }

3016

3019 function_ref<void(unsigned, bool)> printValueName) {

3020 const char *binopSpelling = nullptr;

3021 switch (expr.getKind()) {

3023 unsigned pos = cast(expr).getPosition();

3024 if (printValueName)

3025 printValueName(pos, true);

3026 else

3027 os << 's' << pos;

3028 return;

3029 }

3031 unsigned pos = cast(expr).getPosition();

3032 if (printValueName)

3033 printValueName(pos, false);

3034 else

3035 os << 'd' << pos;

3036 return;

3037 }

3039 os << cast(expr).getValue();

3040 return;

3042 binopSpelling = " + ";

3043 break;

3045 binopSpelling = " * ";

3046 break;

3048 binopSpelling = " floordiv ";

3049 break;

3051 binopSpelling = " ceildiv ";

3052 break;

3054 binopSpelling = " mod ";

3055 break;

3056 }

3057

3058 auto binOp = cast(expr);

3059 AffineExpr lhsExpr = binOp.getLHS();

3060 AffineExpr rhsExpr = binOp.getRHS();

3061

3062

3064 if (enclosingTightness == BindingStrength::Strong)

3065 os << '(';

3066

3067

3068 auto rhsConst = dyn_cast(rhsExpr);

3070 rhsConst.getValue() == -1) {

3071 os << "-";

3072 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);

3073 if (enclosingTightness == BindingStrength::Strong)

3074 os << ')';

3075 return;

3076 }

3077

3078 printAffineExprInternal(lhsExpr, BindingStrength::Strong, printValueName);

3079

3080 os << binopSpelling;

3081 printAffineExprInternal(rhsExpr, BindingStrength::Strong, printValueName);

3082

3083 if (enclosingTightness == BindingStrength::Strong)

3084 os << ')';

3085 return;

3086 }

3087

3088

3089 if (enclosingTightness == BindingStrength::Strong)

3090 os << '(';

3091

3092

3093

3094 if (auto rhs = dyn_cast(rhsExpr)) {

3097 if (auto rrhs = dyn_cast(rrhsExpr)) {

3098 if (rrhs.getValue() == -1) {

3099 printAffineExprInternal(lhsExpr, BindingStrength::Weak,

3100 printValueName);

3101 os << " - ";

3103 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,

3104 printValueName);

3105 } else {

3106 printAffineExprInternal(rhs.getLHS(), BindingStrength::Weak,

3107 printValueName);

3108 }

3109

3110 if (enclosingTightness == BindingStrength::Strong)

3111 os << ')';

3112 return;

3113 }

3114

3115 if (rrhs.getValue() < -1) {

3116 printAffineExprInternal(lhsExpr, BindingStrength::Weak,

3117 printValueName);

3118 os << " - ";

3119 printAffineExprInternal(rhs.getLHS(), BindingStrength::Strong,

3120 printValueName);

3121 os << " * " << -rrhs.getValue();

3122 if (enclosingTightness == BindingStrength::Strong)

3123 os << ')';

3124 return;

3125 }

3126 }

3127 }

3128 }

3129

3130

3131 if (auto rhsConst = dyn_cast(rhsExpr)) {

3132 if (rhsConst.getValue() < 0) {

3133 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);

3134 os << " - " << -rhsConst.getValue();

3135 if (enclosingTightness == BindingStrength::Strong)

3136 os << ')';

3137 return;

3138 }

3139 }

3140

3141 printAffineExprInternal(lhsExpr, BindingStrength::Weak, printValueName);

3142

3143 os << " + ";

3144 printAffineExprInternal(rhsExpr, BindingStrength::Weak, printValueName);

3145

3146 if (enclosingTightness == BindingStrength::Strong)

3147 os << ')';

3148 }

3149

3151 printAffineExprInternal(expr, BindingStrength::Weak);

3152 isEq ? os << " == 0" : os << " >= 0";

3153 }

3154

3156

3157 os << '(';

3158 for (int i = 0; i < (int)map.getNumDims() - 1; ++i)

3159 os << 'd' << i << ", ";

3162 os << ')';

3163

3164

3166 os << '[';

3167 for (unsigned i = 0; i < map.getNumSymbols() - 1; ++i)

3168 os << 's' << i << ", ";

3171 os << ']';

3172 }

3173

3174

3175 os << " -> (";

3177 [&](AffineExpr expr) { printAffineExpr(expr); });

3178 os << ')';

3179 }

3180

3182

3183 os << '(';

3184 for (unsigned i = 1; i < set.getNumDims(); ++i)

3185 os << 'd' << i - 1 << ", ";

3188 os << ')';

3189

3190

3192 os << '[';

3193 for (unsigned i = 0; i < set.getNumSymbols() - 1; ++i)

3194 os << 's' << i << ", ";

3197 os << ']';

3198 }

3199

3200

3201 os << " : (";

3203 for (int i = 1; i < numConstraints; ++i) {

3204 printAffineConstraint(set.getConstraint(i - 1), set.isEq(i - 1));

3205 os << ", ";

3206 }

3207 if (numConstraints >= 1)

3208 printAffineConstraint(set.getConstraint(numConstraints - 1),

3209 set.isEq(numConstraints - 1));

3210 os << ')';

3211 }

3212

3213

3214

3215

3216

3217 namespace {

3218

3220 public:

3223

3224 explicit OperationPrinter(raw_ostream &os, AsmStateImpl &state)

3226

3227

3228 void printTopLevelOperation(Operation *op);

3229

3230

3231

3232 void printFullOpWithIndentAndLoc(Operation *op);

3233

3234

3235 void printFullOp(Operation *op);

3236

3237

3238 void printCustomOrGenericOp(Operation *op) override;

3239

3240 void printGenericOp(Operation *op, bool printOpName) override;

3241

3242

3243 void printBlockName(Block *block);

3244

3245

3246

3247

3248 void print(Block *block, bool printBlockArgs = true,

3249 bool printBlockTerminator = true);

3250

3251

3252 void printValueID(Value value, bool printResultNo = true,

3253 raw_ostream *streamOverride = nullptr) const;

3254

3255

3256 void printOperationID(Operation *op,

3257 raw_ostream *streamOverride = nullptr) const;

3258

3259

3260

3261

3262

3263

3264

3265 void printOptionalLocationSpecifier(Location loc) override {

3266 printTrailingLocation(loc);

3267 }

3268

3269

3270

3272 os << newLine;

3273 os.indent(currentIndent);

3274 }

3275

3276

3277 void increaseIndent() override { currentIndent += indentWidth; }

3278

3279

3280 void decreaseIndent() override { currentIndent -= indentWidth; }

3281

3282

3283

3284

3285

3286

3289 bool omitType = false) override;

3290

3291

3292 void printOperand(Value value) override { printValueID(value); }

3293 void printOperand(Value value, raw_ostream &os) override {

3294 printValueID(value, true, &os);

3295 }

3296

3297

3301 }

3302 void printOptionalAttrDictWithKeyword(

3306 true);

3307 }

3308

3309

3310 void printSuccessor(Block *successor) override;

3311

3312

3313

3314 void printSuccessorAndUseList(Block *successor,

3316

3317

3319 bool printBlockTerminators, bool printEmptyBlock) override;

3320

3321

3322

3323

3324

3325 void shadowRegionArgs(Region &region, ValueRange namesToUse) override {

3326 state.getSSANameState().shadowRegionArgs(region, namesToUse);

3327 }

3328

3329

3330

3331 void printAffineMapOfSSAIds(AffineMapAttr mapAttr,

3333

3334

3335

3338

3339

3340 void printUsersComment(Operation *op);

3341

3342

3344

3345

3346 void printValueUsers(Value value);

3347

3348

3349

3350 void printUserIDs(Operation *user, bool prefixComma = false);

3351

3352 private:

3353

3354

3356 public:

3357 using ValueFn = function_ref<void(raw_ostream &)>;

3358 using PrintFn = function_ref<void(StringRef, ValueFn)>;

3359

3360 ResourceBuilder(PrintFn printFn) : printFn(printFn) {}

3361 ~ResourceBuilder() override = default;

3362

3363 void buildBool(StringRef key, bool data) final {

3364 printFn(key, [&](raw_ostream &os) { os << (data ? "true" : "false"); });

3365 }

3366

3367 void buildString(StringRef key, StringRef data) final {

3368 printFn(key, [&](raw_ostream &os) {

3369 os << "\"";

3370 llvm::printEscapedString(data, os);

3371 os << "\"";

3372 });

3373 }

3374

3376 uint32_t dataAlignment) final {

3377 printFn(key, [&](raw_ostream &os) {

3378

3379 llvm::support::ulittle32_t dataAlignmentLE(dataAlignment);

3380 os << "\"0x"

3381 << llvm::toHex(StringRef(reinterpret_cast<char *>(&dataAlignmentLE),

3382 sizeof(dataAlignment)))

3383 << llvm::toHex(StringRef(data.data(), data.size())) << "\"";

3384 });

3385 }

3386

3387 private:

3388 PrintFn printFn;

3389 };

3390

3391

3392 void printFileMetadataDictionary(Operation *op);

3393

3394

3395

3396

3397

3398 void printResourceFileMetadata(function_ref<void()> checkAddMetadataDict,

3400

3401

3402

3403

3404

3405

3407

3408

3409 const static unsigned indentWidth = 2;

3410

3411

3412 unsigned currentIndent = 0;

3413 };

3414 }

3415

3416 void OperationPrinter::printTopLevelOperation(Operation *op) {

3417

3418 state.getAliasState().printNonDeferredAliases(*this, newLine);

3419

3420

3421 printFullOpWithIndentAndLoc(op);

3422 os << newLine;

3423

3424

3425 state.getAliasState().printDeferredAliases(*this, newLine);

3426

3427

3428 printFileMetadataDictionary(op);

3429 }

3430

3431 void OperationPrinter::printFileMetadataDictionary(Operation *op) {

3432 bool sawMetadataEntry = false;

3433 auto checkAddMetadataDict = [&] {

3434 if (!std::exchange(sawMetadataEntry, true))

3435 os << newLine << "{-#" << newLine;

3436 };

3437

3438

3439 printResourceFileMetadata(checkAddMetadataDict, op);

3440

3441

3442 if (sawMetadataEntry)

3443 os << newLine << "#-}" << newLine;

3444 }

3445

3446 void OperationPrinter::printResourceFileMetadata(

3448

3449 bool hadResource = false;

3450 bool needResourceComma = false;

3451 bool needEntryComma = false;

3452 auto processProvider = [&](StringRef dictName, StringRef name, auto &provider,

3453 auto &&...providerArgs) {

3454 bool hadEntry = false;

3455 auto printFn = [&](StringRef key, ResourceBuilder::ValueFn valueFn) {

3456 checkAddMetadataDict();

3457

3458 std::string resourceStr;

3459 auto printResourceStr = [&](raw_ostream &os) { os << resourceStr; };

3460 std::optional<uint64_t> charLimit =

3462 if (charLimit.has_value()) {

3463

3464 if (charLimit.value() == 0)

3465 return;

3466

3467 llvm::raw_string_ostream ss(resourceStr);

3468 valueFn(ss);

3469

3470

3471 if (resourceStr.size() > charLimit.value())

3472 return;

3473

3474

3475 valueFn = printResourceStr;

3476 }

3477

3478

3479 if (!std::exchange(hadResource, true)) {

3480 if (needResourceComma)

3481 os << "," << newLine;

3482 os << " " << dictName << "_resources: {" << newLine;

3483 }

3484

3485 if (!std::exchange(hadEntry, true)) {

3486 if (needEntryComma)

3487 os << "," << newLine;

3488 os << " " << name << ": {" << newLine;

3489 } else {

3490 os << "," << newLine;

3491 }

3492 os << " ";

3494 os << ": ";

3495

3496 valueFn(os);

3497 };

3498 ResourceBuilder entryBuilder(printFn);

3499 provider.buildResources(op, providerArgs..., entryBuilder);

3500

3501 needEntryComma |= hadEntry;

3502 if (hadEntry)

3503 os << newLine << " }";

3504 };

3505

3506

3507

3509 auto &dialectResources = state.getDialectResources();

3510 StringRef name = interface.getDialect()->getNamespace();

3511 auto it = dialectResources.find(interface.getDialect());

3512 if (it != dialectResources.end())

3513 processProvider("dialect", name, interface, it->second);

3514 else

3515 processProvider("dialect", name, interface,

3517 }

3518 if (hadResource)

3519 os << newLine << " }";

3520

3521

3522

3523 needEntryComma = false;

3524 needResourceComma = hadResource;

3525 hadResource = false;

3526 for (const auto &printer : state.getResourcePrinters())

3527 processProvider("external", printer.getName(), printer);

3528 if (hadResource)

3529 os << newLine << " }";

3530 }

3531

3532

3533

3534

3535

3536

3537 void OperationPrinter::printRegionArgument(BlockArgument arg,

3539 bool omitType) {

3540 printOperand(arg);

3541 if (!omitType) {

3542 os << ": ";

3544 }

3545 printOptionalAttrDict(argAttrs);

3546

3547 printTrailingLocation(arg.getLoc(), false);

3548 }

3549

3550 void OperationPrinter::printFullOpWithIndentAndLoc(Operation *op) {

3551

3552 state.registerOperationLocation(op, newLine.curLine, currentIndent);

3553

3554 os.indent(currentIndent);

3555 printFullOp(op);

3556 printTrailingLocation(op->getLoc());

3558 printUsersComment(op);

3559 }

3560

3561 void OperationPrinter::printFullOp(Operation *op) {

3563 auto printResultGroup = [&](size_t resultNo, size_t resultCount) {

3564 printValueID(op->getResult(resultNo), false);

3565 if (resultCount > 1)

3566 os << ':' << resultCount;

3567 };

3568

3569

3570 ArrayRef resultGroups = state.getSSANameState().getOpResultGroups(op);

3571 if (!resultGroups.empty()) {

3572

3573

3574 interleaveComma(llvm::seq(0, resultGroups.size() - 1), [&](int i) {

3575 printResultGroup(resultGroups[i],

3576 resultGroups[i + 1] - resultGroups[i]);

3577 });

3578 os << ", ";

3579 printResultGroup(resultGroups.back(), numResults - resultGroups.back());

3580

3581 } else {

3582 printResultGroup(0, numResults);

3583 }

3584

3585 os << " = ";

3586 }

3587

3588 printCustomOrGenericOp(op);

3589 }

3590

3591 void OperationPrinter::printUsersComment(Operation *op) {

3594 os << " // id: ";

3595 printOperationID(op);

3596 } else if (numResults && op->use_empty()) {

3597 os << " // unused";

3598 } else if (numResults && !op->use_empty()) {

3599

3600

3601 unsigned usedInNResults = 0;

3602 unsigned usedInNOperations = 0;

3605 if (userSet.insert(user).second) {

3606 ++usedInNOperations;

3607 usedInNResults += user->getNumResults();

3608 }

3609 }

3610

3611

3612 bool exactlyOneUniqueUse =

3613 usedInNResults <= 1 && usedInNOperations <= 1 && numResults == 1;

3614 os << " // " << (exactlyOneUniqueUse ? "user" : "users") << ": ";

3615 bool shouldPrintBrackets = numResults > 1;

3616 auto printOpResult = [&](OpResult opResult) {

3617 if (shouldPrintBrackets)

3618 os << "(";

3619 printValueUsers(opResult);

3620 if (shouldPrintBrackets)

3621 os << ")";

3622 };

3623

3624 interleaveComma(op->getResults(), printOpResult);

3625 }

3626 }

3627

3628 void OperationPrinter::printUsersComment(BlockArgument arg) {

3629 os << "// ";

3630 printValueID(arg);

3632 os << " is unused";

3633 } else {

3634 os << " is used by ";

3635 printValueUsers(arg);

3636 }

3637 os << newLine;

3638 }

3639

3640 void OperationPrinter::printValueUsers(Value value) {

3642 os << "unused";

3643

3644

3645

3648 if (userSet.insert(user).second)

3649 printUserIDs(user, index);

3650 }

3651 }

3652

3653 void OperationPrinter::printUserIDs(Operation *user, bool prefixComma) {

3654 if (prefixComma)

3655 os << ", ";

3656

3658 printOperationID(user);

3659 } else {

3661 [this](Value result) { printValueID(result); });

3662 }

3663 }

3664

3665 void OperationPrinter::printCustomOrGenericOp(Operation *op) {

3666

3668

3669

3671 opInfo->printAssembly(op, *this, defaultDialectStack.back());

3672 return;

3673 }

3674

3676 if (auto opPrinter = dialect->getOperationPrinter(op)) {

3677

3679

3680

3681 if (name.count('.') == 1)

3682 name.consume_front((defaultDialectStack.back() + ".").str());

3683 os << name;

3684

3685

3686 opPrinter(op, *this);

3687 return;

3688 }

3689 }

3690 }

3691

3692

3693 printGenericOp(op, true);

3694 }

3695

3696 void OperationPrinter::printGenericOp(Operation *op, bool printOpName) {

3697 if (printOpName)

3699 os << '(';

3700 interleaveComma(op->getOperands(), [&](Value value) { printValueID(value); });

3701 os << ')';

3702

3703

3705 os << '[';

3707 [&](Block *successor) { printBlockName(successor); });

3708 os << ']';

3709 }

3710

3711

3713 os << " <";

3715 os << '>';

3716 }

3717

3718 // Print regions.

3719 if (op->getNumRegions() != 0) {

3720 os << " (";

3721 interleaveComma(op->getRegions(), [&](Region &region) {

3722 printRegion(region, /*printEntryBlockArgs=*/true,

3723 /*printBlockTerminators=*/true, /*printEmptyBlock=*/true);

3724 });

3725 os << ')';

3726 }

3727

3728 printOptionalAttrDict(op->getPropertiesStorage()

3729 ? llvm::to_vector(op->getDiscardableAttrs())

3730 : op->getAttrs());

3731

3732 // Print the type signature of the operation.

3733 os << " : ";

3734 printFunctionalType(op);

3735 }

3736

3737 void OperationPrinter::printBlockName(Block *block) {

3738 os << state.getSSANameState().getBlockInfo(block).name;

3739 }

3740

3741 void OperationPrinter::print(Block *block, bool printBlockArgs,

3742 bool printBlockTerminator) {

3743 // Print the block label and argument list if requested.

3744 if (printBlockArgs) {

3745 os.indent(currentIndent);

3746 printBlockName(block);

3747

3748 // Print the argument list if non-empty.

3749 if (!block->args_empty()) {

3750 os << '(';

3751 interleaveComma(block->getArguments(), [&](BlockArgument arg) {

3752 printValueID(arg);

3753 os << ": ";

3754 printType(arg.getType());

3755 // TODO: We should allow location aliases on block arguments.

3756 printTrailingLocation(arg.getLoc(), /*allowAlias*/ false);

3757 });

3758 os << ')';

3759 }

3760 os << ':';

3761

3762 // Print out some context information about the predecessors of this block.

3763 if (!block->getParent()) {

3764 os << " // block is not in a region!";

3765 } else if (block->hasNoPredecessors()) {

3766 if (!block->isEntryBlock())

3767 os << " // no predecessors";

3768 } else if (auto *pred = block->getSinglePredecessor()) {

3769 os << " // pred: ";

3770 printBlockName(pred);

3771 } else {

3772 // We want to print the predecessors in a stable order, not in

3773 // whatever order the use-list is in, so gather and sort them.

3774 SmallVector<BlockInfo, 4> predIDs;

3775 for (auto *pred : block->getPredecessors())

3776 predIDs.push_back(state.getSSANameState().getBlockInfo(pred));

3777 llvm::sort(predIDs, [](BlockInfo lhs, BlockInfo rhs) {

3778 return lhs.ordering < rhs.ordering;

3779 });

3780

3781 os << " // " << predIDs.size() << " preds: ";

3782

3783 interleaveComma(predIDs, [&](BlockInfo pred) { os << pred.name; });

3784 }

3785 os << newLine;

3786 }

3787

3788 currentIndent += indentWidth;

3789

3790 if (printerFlags.shouldPrintValueUsers()) {

3791 for (BlockArgument arg : block->getArguments()) {

3792 os.indent(currentIndent);

3793 printUsersComment(arg);

3794 }

3795 }

3796

3797 bool hasTerminator =

3798 !block->empty() && block->back().hasTraitOpTrait::IsTerminator();

3799 auto range = llvm::make_range(

3800 block->begin(),

3801 std::prev(block->end(),

3802 (!hasTerminator || printBlockTerminator) ? 0 : 1));

3803 for (auto &op : range) {

3804 printFullOpWithIndentAndLoc(&op);

3805 os << newLine;

3806 }

3807 currentIndent -= indentWidth;

3808 }

3809

3810 void OperationPrinter::printValueID(Value value, bool printResultNo,

3811 raw_ostream *streamOverride) const {

3812 state.getSSANameState().printValueID(value, printResultNo,

3813 streamOverride ? *streamOverride : os);

3814 }

3815

3816 void OperationPrinter::printOperationID(Operation *op,

3817 raw_ostream *streamOverride) const {

3818 state.getSSANameState().printOperationID(op, streamOverride ? *streamOverride

3819 : os);

3820 }

3821

3822 void OperationPrinter::printSuccessor(Block *successor) {

3823 printBlockName(successor);

3824 }

3825

3826 void OperationPrinter::printSuccessorAndUseList(Block *successor,

3827 ValueRange succOperands) {

3828 printBlockName(successor);

3829 if (succOperands.empty())

3830 return;

3831

3832 os << '(';

3833 interleaveComma(succOperands,

3834 [this](Value operand) { printValueID(operand); });

3835 os << " : ";

3836 interleaveComma(succOperands,

3837 [this](Value operand) { printType(operand.getType()); });

3838 os << ')';

3839 }

3840

3841 void OperationPrinter::printRegion(Region &region, bool printEntryBlockArgs,

3842 bool printBlockTerminators,

3843 bool printEmptyBlock) {

3844 if (printerFlags.shouldSkipRegions()) {

3845 os << "{...}";

3846 return;

3847 }

3848 os << "{" << newLine;

3849 if (!region.empty()) {

3850 auto restoreDefaultDialect =

3851 llvm::make_scope_exit([&]() { defaultDialectStack.pop_back(); });

3852 if (auto iface = dyn_cast(region.getParentOp()))

3853 defaultDialectStack.push_back(iface.getDefaultDialect());

3854 else

3855 defaultDialectStack.push_back("");

3856

3857 auto *entryBlock = &region.front();

3858 // Force printing the block header if printEmptyBlock is set and the block

3859 // is empty or if printEntryBlockArgs is set and there are arguments to

3860 // print.

3861 bool shouldAlwaysPrintBlockHeader =

3862 (printEmptyBlock && entryBlock->empty()) ||

3863 (printEntryBlockArgs && entryBlock->getNumArguments() != 0);

3864 print(entryBlock, shouldAlwaysPrintBlockHeader, printBlockTerminators);

3865 for (auto &b : llvm::drop_begin(region.getBlocks(), 1))

3866 print(&b);

3867 }

3868 os.indent(currentIndent) << "}";

3869 }

3870

3871 void OperationPrinter::printAffineMapOfSSAIds(AffineMapAttr mapAttr,

3872 ValueRange operands) {

3873 if (!mapAttr) {

3874 os << "<>";

3875 return;

3876 }

3877 AffineMap map = mapAttr.getValue();

3878 unsigned numDims = map.getNumDims();

3879 auto printValueName = [&](unsigned pos, bool isSymbol) {

3880 unsigned index = isSymbol ? numDims + pos : pos;

3881 assert(index < operands.size());

3882 if (isSymbol)

3883 os << "symbol(";

3884 printValueID(operands[index]);

3885 if (isSymbol)

3886 os << ')';

3887 };

3888

3889 interleaveComma(map.getResults(), [&](AffineExpr expr) {

3890 printAffineExpr(expr, printValueName);

3891 });

3892 }

3893

3894 void OperationPrinter::printAffineExprOfSSAIds(AffineExpr expr,

3895 ValueRange dimOperands,

3896 ValueRange symOperands) {

3897 auto printValueName = [&](unsigned pos, bool isSymbol) {

3898 if (!isSymbol)

3899 return printValueID(dimOperands[pos]);

3900 os << "symbol(";

3901 printValueID(symOperands[pos]);

3902 os << ')';

3903 };

3904 printAffineExpr(expr, printValueName);

3905 }

3906

3907 //===----------------------------------------------------------------------===//

3908 // print and dump methods

3909 //===----------------------------------------------------------------------===//

3910

3911 void Attribute::print(raw_ostream &os, bool elideType) const {

3912 if (!*this) {

3913 os << "<>";

3914 return;

3915 }

3916

3917 AsmState state(getContext());

3918 print(os, state, elideType);

3919 }

3920 void Attribute::print(raw_ostream &os, AsmState &state, bool elideType) const {

3921 using AttrTypeElision = AsmPrinter::Impl::AttrTypeElision;

3922 AsmPrinter::Impl(os, state.getImpl())

3923 .printAttribute(*this, elideType ? AttrTypeElision::Must

3924 : AttrTypeElision::Never);

3925 }

3926

3927 void Attribute::dump() const {

3928 print(llvm::errs());

3929 llvm::errs() << "\n";

3930 }

3931

3932 void Attribute::printStripped(raw_ostream &os, AsmState &state) const {

3933 if (!*this) {

3934 os << "<>";

3935 return;

3936 }

3937

3938 AsmPrinter::Impl subPrinter(os, state.getImpl());

3939 if (succeeded(subPrinter.printAlias(*this)))

3940 return;

3941

3942 auto &dialect = this->getDialect();

3943 uint64_t posPrior = os.tell();

3944 DialectAsmPrinter printer(subPrinter);

3945 dialect.printAttribute(*this, printer);

3946 if (posPrior != os.tell())

3947 return;

3948

3949 // Fallback to printing with prefix if the above failed to write anything

3950 // to the output stream.

3951 print(os, state);

3952 }

3953 void Attribute::printStripped(raw_ostream &os) const {

3954 if (!*this) {

3955 os << "<>";

3956 return;

3957 }

3958

3959 AsmState state(getContext());

3960 printStripped(os, state);

3961 }

3962

3963 void Type::print(raw_ostream &os) const {

3964 if (!*this) {

3965 os << "<>";

3966 return;

3967 }

3968

3969 AsmState state(getContext());

3970 print(os, state);

3971 }

3972 void Type::print(raw_ostream &os, AsmState &state) const {

3973 AsmPrinter::Impl(os, state.getImpl()).printType(*this);

3974 }

3975

3976 void Type::dump() const {

3977 print(llvm::errs());

3978 llvm::errs() << "\n";

3979 }

3980

3981 void AffineMap::dump() const {

3982 print(llvm::errs());

3983 llvm::errs() << "\n";

3984 }

3985

3986 void IntegerSet::dump() const {

3987 print(llvm::errs());

3988 llvm::errs() << "\n";

3989 }

3990

3991 void AffineExpr::print(raw_ostream &os) const {

3992 if (!expr) {

3993 os << "<>";

3994 return;

3995 }

3996 AsmState state(getContext());

3997 AsmPrinter::Impl(os, state.getImpl()).printAffineExpr(*this);

3998 }

3999

4000 void AffineExpr::dump() const {

4001 print(llvm::errs());

4002 llvm::errs() << "\n";

4003 }

4004

4005 void AffineMap::print(raw_ostream &os) const {

4006 if (!map) {

4007 os << "<>";

4008 return;

4009 }

4010 AsmState state(getContext());

4011 AsmPrinter::Impl(os, state.getImpl()).printAffineMap(*this);

4012 }

4013

4014 void IntegerSet::print(raw_ostream &os) const {

4015 AsmState state(getContext());

4016 AsmPrinter::Impl(os, state.getImpl()).printIntegerSet(*this);

4017 }

4018

4019 void Value::print(raw_ostream &os) const { print(os, OpPrintingFlags()); }

4020 void Value::print(raw_ostream &os, const OpPrintingFlags &flags) const {

4021 if (!impl) {

4022 os << "<>";

4023 return;

4024 }

4025

4026 if (auto *op = getDefiningOp())

4027 return op->print(os, flags);

4028 // TODO: Improve BlockArgument print'ing.

4029 BlockArgument arg = llvm::cast(*this);

4030 os << " of type '" << arg.getType()

4032 }

4034 if (impl) {

4035 os << "<>";

4036 return;

4037 }

4038

4039 if (auto *op = getDefiningOp())

4040 return op->print(os, state);

4041

4042

4043 BlockArgument arg = llvm::cast(*this);

4044 os << " of type '" << arg.getType()

4046 }

4047

4049 print(llvm::errs());

4050 llvm::errs() << "\n";

4051 }

4052

4054

4055

4056

4057

4058 state.getImpl().getSSANameState().printValueID(*this, true,

4059 os);

4060 }

4061

4063 do {

4064

4065

4067 break;

4068

4069

4071 if (!parentOp)

4072 break;

4073 op = parentOp;

4074 } while (true);

4075 return op;

4076 }

4077

4081 if (auto result = llvm::dyn_cast(*this)) {

4083 } else {

4084 op = llvm::cast(*this).getOwner()->getParentOp();

4085 if (!op) {

4086 os << "<>";

4087 return;

4088 }

4089 }

4092 printAsOperand(os, state);

4093 }

4094

4096

4098 AsmState state(op, printerFlags);

4099 print(os, state);

4100 }

4102 OperationPrinter printer(os, state.getImpl());

4103 if (!getParent() && !state.getPrinterFlags().shouldUseLocalScope()) {

4104 state.getImpl().initializeAliases(this);

4105 printer.printTopLevelOperation(this);

4106 } else {

4107 printer.printFullOpWithIndentAndLoc(this);

4108 }

4109 }

4110

4113 llvm::errs() << "\n";

4114 }

4115

4118 llvm::errs() << "\n";

4119 }

4120

4122 Operation *parentOp = getParentOp();

4123 if (!parentOp) {

4124 os << "<>\n";

4125 return;

4126 }

4127

4128 while (auto *nextOp = parentOp->getParentOp())

4129 parentOp = nextOp;

4130

4132 print(os, state);

4133 }

4135 OperationPrinter(os, state.getImpl()).print(this);

4136 }

4137

4139

4140

4142 Operation *parentOp = getParentOp();

4143 if (!parentOp) {

4144 os << "<>\n";

4145 return;

4146 }

4148 printAsOperand(os, state);

4149 }

4151 OperationPrinter printer(os, state.getImpl());

4152 printer.printBlockName(this);

4153 }

4154

4156 block.print(os);

4157 return os;

4158 }

4159

4160

4161

4162

4163 namespace mlir {

4164

4167 if (dimensions.empty())

4168 printer << "[";

4170 if (dimensions.empty())

4171 printer << "]";

4172 }

4173

4176

4180 << "Failed parsing dimension list.";

4181 }

4182 dimensions =

4184 return success();

4185 }

4186

4187

4191 << "Failed parsing dimension list.";

4192 }

4193 if (shapeArr.empty()) {

4195 << "Failed parsing dimension list. Did you mean an empty list? It "

4196 "must be denoted by \"[]\".";

4197 }

4199 return success();

4200 }

4201

4202 }

static void printSymbolReference(StringRef symbolRef, raw_ostream &os)

Print the given string as a symbol reference.

static void printFloatValue(const APFloat &apValue, raw_ostream &os, bool *printedHex=nullptr)

Print a floating point value in a way that the parser will be able to round-trip losslessly.

static StringRef sanitizeIdentifier(StringRef name, SmallString< 16 > &buffer, StringRef allowedPunctChars="$._-")

Sanitize the given name such that it can be used as a valid identifier.

static llvm::ManagedStatic< AsmPrinterOptions > clOptions

static Operation * findParent(Operation *op, bool shouldUseLocalScope)

static void printKeywordOrString(StringRef keyword, raw_ostream &os)

Print the given string as a keyword, or a quoted and escaped string if it has any special or non-prin...

static bool isDialectSymbolSimpleEnoughForPrettyForm(StringRef symName)

Returns true if the given dialect symbol data is simple enough to print in the pretty form.

static void printDialectSymbol(raw_ostream &os, StringRef symPrefix, StringRef dialectName, StringRef symString)

Print the given dialect symbol to the stream.

static OpPrintingFlags verifyOpAndAdjustFlags(Operation *op, OpPrintingFlags printerFlags)

Verifies the operation and switches to generic op printing if verification fails.

MLIR_CRUNNERUTILS_EXPORT void printString(char const *s)

MLIR_CRUNNERUTILS_EXPORT void printNewline()

static void visit(Operation *op, DenseSet< Operation * > &visited)

Visits all the pdl.operand(s), pdl.result(s), and pdl.operation(s) connected to the given operation.

static MLIRContext * getContext(OpFoldResult val)

union mlir::linalg::@1203::ArityGroupAndKind::Kind kind

static std::string diag(const llvm::Value &value)

static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)

static void printRegion(llvm::raw_ostream &os, Region *region, OpPrintingFlags &flags)

Base type for affine expression.

AffineExprKind getKind() const

Return the classification for this type.

A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.

unsigned getNumSymbols() const

unsigned getNumDims() const

ArrayRef< AffineExpr > getResults() const

This class represents an opaque handle to a dialect resource entry.

This class represents a single parsed resource entry.

virtual FailureOr< AsmResourceBlob > parseAsBlob(BlobAllocatorFn allocator) const =0

Parse the resource entry represented by a binary blob.

virtual InFlightDiagnostic emitError() const =0

Emit an error at the location of this entry.

virtual AsmResourceEntryKind getKind() const =0

Return the kind of this value.

virtual FailureOr< std::string > parseAsString() const =0

Parse the resource entry represented by a human-readable string.

virtual FailureOr< bool > parseAsBool() const =0

Parse the resource entry represented by a boolean.

virtual StringRef getKey() const =0

Return the key of the resource entry.

MLIRContext * getContext() const

virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0

Emit a diagnostic at the specified location and return failure.

virtual ParseResult parseRSquare()=0

Parse a ] token.

virtual ParseResult parseDimensionList(SmallVectorImpl< int64_t > &dimensions, bool allowDynamic=true, bool withTrailingX=true)=0

Parse a dimension list of a tensor or memref type.

virtual SMLoc getCurrentLocation()=0

Get the location of the next token and store it into the argument.

ParseResult parseTypeList(SmallVectorImpl< Type > &result)

Parse a type list.

virtual ParseResult parseOptionalLSquare()=0

Parse a [ token if present.

Impl(raw_ostream &os, AsmStateImpl &state)

BindingStrength

This enum is used to represent the binding strength of the enclosing context that an AffineExprStorag...

void printHexString(StringRef str)

Print a hex string, wrapped with "".

void printDenseArrayAttr(DenseArrayAttr attr)

Print a dense array attribute.

void printDenseElementsAttr(DenseElementsAttr attr, bool allowHex)

Print a dense elements attribute.

void printAttribute(Attribute attr, AttrTypeElision typeElision=AttrTypeElision::Never)

Print the given attribute or an alias.

void printDimensionList(ArrayRef< int64_t > shape)

OpPrintingFlags printerFlags

A set of flags to control the printer's behavior.

raw_ostream & os

The output stream for the printer.

void printResourceHandle(const AsmDialectResourceHandle &resource)

Print a reference to the given resource that is owned by the given dialect.

raw_ostream & getStream()

Returns the output stream of the printer.

LogicalResult printAlias(Attribute attr)

Print the alias for the given attribute, return failure if no alias could be printed.

void printDialectAttribute(Attribute attr)

void interleaveComma(const Container &c, UnaryFunctor eachFn) const

void printDialectType(Type type)

void printLocation(LocationAttr loc, bool allowAlias=false)

Print the given location to the stream.

AsmStateImpl & state

An underlying assembly printer state.

void printAffineMap(AffineMap map)

void printTrailingLocation(Location loc, bool allowAlias=true)

void printAffineExprInternal(AffineExpr expr, BindingStrength enclosingTightness, function_ref< void(unsigned, bool)> printValueName=nullptr)

void printEscapedString(StringRef str)

Print an escaped string, wrapped with "".

void printAffineExpr(AffineExpr expr, function_ref< void(unsigned, bool)> printValueName=nullptr)

void printDenseStringElementsAttr(DenseStringElementsAttr attr)

Print a dense string elements attribute.

void printAttributeImpl(Attribute attr, AttrTypeElision typeElision=AttrTypeElision::Never)

Print the given attribute without considering an alias.

void printAffineConstraint(AffineExpr expr, bool isEq)

void printDenseIntOrFPElementsAttr(DenseIntOrFPElementsAttr attr, bool allowHex)

Print a dense elements attribute.

AttrTypeElision

This enum describes the different kinds of elision for the type of an attribute when printing it.

@ May

The type may be elided when it matches the default used in the parser (for example i64 is the default...

@ Never

The type must not be elided,.

@ Must

The type must be elided.

LogicalResult pushCyclicPrinting(const void *opaquePointer)

void printIntegerSet(IntegerSet set)

NewLineCounter newLine

A tracker for the number of new lines emitted during printing.

void printOptionalAttrDict(ArrayRef< NamedAttribute > attrs, ArrayRef< StringRef > elidedAttrs={}, bool withKeyword=false)

void printType(Type type)

Print the given type or an alias.

void printLocationInternal(LocationAttr loc, bool pretty=false, bool isTopLevel=false)

void printTypeImpl(Type type)

Print the given type.

void printNamedAttribute(NamedAttribute attr)

virtual void printAttributeWithoutType(Attribute attr)

Print the given attribute without its type.

virtual LogicalResult printAlias(Attribute attr)

Print the alias for the given attribute, return failure if no alias could be printed.

virtual void popCyclicPrinting()

Removes the element that was last inserted with a successful call to pushCyclicPrinting.

virtual LogicalResult pushCyclicPrinting(const void *opaquePointer)

Pushes a new attribute or type in the form of a type erased pointer into an internal set.

virtual void printType(Type type)

virtual void printKeywordOrString(StringRef keyword)

Print the given string as a keyword, or a quoted and escaped string if it has any special or non-prin...

virtual void printSymbolName(StringRef symbolRef)

Print the given string as a symbol reference, i.e.

virtual void printString(StringRef string)

Print the given string as a quoted string, escaping any special or non-printable characters in it.

virtual void printAttribute(Attribute attr)

void printDimensionList(ArrayRef< int64_t > shape)

virtual raw_ostream & getStream() const

Return the raw output stream used by this printer.

virtual void printResourceHandle(const AsmDialectResourceHandle &resource)

Print a handle to the given dialect resource.

virtual void printFloat(const APFloat &value)

Print the given floating point value in a stabilized form that can be roundtripped through the IR.

This class is used to build resource entries for use by the printer.

virtual void buildString(StringRef key, StringRef data)=0

Build a resource entry represented by the given human-readable string value.

virtual void buildBool(StringRef key, bool data)=0

Build a resource entry represented by the given bool.

virtual void buildBlob(StringRef key, ArrayRef< char > data, uint32_t dataAlignment)=0

Build an resource entry represented by the given binary blob data.

This class represents an instance of a resource parser.

static std::unique_ptr< AsmResourcePrinter > fromCallable(StringRef name, CallableT &&printFn)

Return a resource printer implemented via the given callable, whose form should match that of buildRe...

This class provides management for the lifetime of the state used when printing the IR.

void attachResourcePrinter(std::unique_ptr< AsmResourcePrinter > printer)

Attach the given resource printer to the AsmState.

DenseMap< Dialect *, SetVector< AsmDialectResourceHandle > > & getDialectResources() const

Returns a map of dialect resources that were referenced when using this state to print IR.

void attachFallbackResourcePrinter(FallbackAsmResourceMap &map)

Attach resource printers to the AsmState for the fallback resources in the given map.

const OpPrintingFlags & getPrinterFlags() const

Get the printer flags.

Attributes are known-constant values of operations.

Dialect & getDialect() const

Get the dialect this attribute is registered to.

bool hasTrait()

Returns true if the type was registered with a particular trait.

const void * getAsOpaquePointer() const

Get an opaque pointer to the attribute.

static Attribute getFromOpaquePointer(const void *ptr)

Construct an attribute from the opaque pointer representation.

This class represents an argument of a Block.

Location getLoc() const

Return the location for this argument.

unsigned getArgNumber() const

Returns the number of this argument.

Block represents an ordered list of Operations.

void printAsOperand(raw_ostream &os, bool printType=true)

Print out the name of the block without printing its body.

void print(raw_ostream &os)

BlockArgListType getArguments()

bool isEntryBlock()

Return if this block is the entry block in the parent region.

Operation * getParentOp()

Returns the closest surrounding operation that contains this block.

An attribute that represents a reference to a dense vector or tensor object.

This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine.

~DialectAsmParser() override

This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...

~DialectAsmPrinter() override

A collection of dialect interfaces within a context, for a given concrete interface type.

Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...

virtual void printAttribute(Attribute, DialectAsmPrinter &) const

Print an attribute registered to this dialect.

virtual void printType(Type, DialectAsmPrinter &) const

Print a type registered to this dialect.

An attribute that associates a referenced attribute with a unique identifier.

A fallback map containing external resources not explicitly handled by another parser/printer.

std::vector< std::unique_ptr< AsmResourcePrinter > > getPrinters()

Build a set of resource printers to print the resources within this map.

An integer set representing a conjunction of one or more affine equalities and inequalities.

unsigned getNumDims() const

unsigned getNumConstraints() const

AffineExpr getConstraint(unsigned idx) const

bool isEq(unsigned idx) const

Returns true if the idx^th constraint is an equality, false if it is an inequality.

unsigned getNumSymbols() const

Location objects represent source locations information in MLIR.

T findInstanceOf()

Return an instance of the given location type if one is nested under the current location.

This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...

MLIRContext is the top-level object for a collection of MLIR operations.

NamedAttribute represents a combination of a name and an Attribute value.

Attribute getValue() const

Return the value of the attribute.

virtual LogicalResult parseResource(AsmParsedResourceEntry &entry) const

Hook for parsing resource entries.

The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...

This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...

void printFunctionalType(Operation *op)

Print the complete type of an operation in functional form.

Set of flags used to control the behavior of the various IR print methods (e.g.

bool shouldElideElementsAttr(ElementsAttr attr) const

Return if the given ElementsAttr should be elided.

std::optional< int64_t > getLargeElementsAttrLimit() const

Return the size limit for printing large ElementsAttr.

bool shouldUseNameLocAsPrefix() const

Return if the printer should use NameLocs as prefixes when printing SSA IDs.

bool shouldAssumeVerified() const

Return if operation verification should be skipped.

OpPrintingFlags & printLargeElementsAttrWithHex(int64_t largeElementLimit=100)

Enables the printing of large element attributes with a hex string.

bool shouldUseLocalScope() const

Return if the printer should use local scope when dumping the IR.

bool shouldPrintDebugInfoPrettyForm() const

Return if debug information should be printed in the pretty form.

bool shouldPrintElementsAttrWithHex(ElementsAttr attr) const

Return if the given ElementsAttr should be printed as hex string.

bool shouldPrintUniqueSSAIDs() const

Return if printer should use unique SSA IDs.

bool shouldPrintValueUsers() const

Return if the printer should print users of values.

int64_t getLargeElementsAttrHexLimit() const

Return the size limit for printing large ElementsAttr as hex string.

bool shouldPrintGenericOpForm() const

Return if operations should be printed in the generic form.

OpPrintingFlags & elideLargeResourceString(int64_t largeResourceLimit=64)

Enables the elision of large resources strings by omitting them from the dialect_resources section.

bool shouldPrintDebugInfo() const

Return if debug information should be printed.

OpPrintingFlags & elideLargeElementsAttrs(int64_t largeElementLimit=16)

Enables the elision of large elements attributes by printing a lexically valid but otherwise meaningl...

OpPrintingFlags & printNameLocAsPrefix(bool enable=true)

Print SSA IDs using their NameLoc, if provided, as prefix.

OpPrintingFlags & printValueUsers(bool enable=true)

Print users of values as comments.

OpPrintingFlags & enableDebugInfo(bool enable=true, bool prettyForm=false)

Enable or disable printing of debug information (based on enable).

OpPrintingFlags()

Initialize the printing flags with default supplied by the cl::opts above.

bool shouldSkipRegions() const

Return if regions should be skipped.

OpPrintingFlags & printGenericOpForm(bool enable=true)

Always print operations in the generic form.

OpPrintingFlags & useLocalScope(bool enable=true)

Use local scope when printing the operation.

std::optional< uint64_t > getLargeResourceStringLimit() const

Return the size limit in chars for printing large resources.

OpPrintingFlags & assumeVerified(bool enable=true)

Do not verify the operation when using custom operation printers.

OpPrintingFlags & skipRegions(bool skip=true)

Skip printing regions.

OpPrintingFlags & printUniqueSSAIDs(bool enable=true)

Print unique SSA ID numbers for values, block arguments and naming conflicts across all regions.

This is a value defined by a result of an operation.

Operation * getOwner() const

Returns the operation that owns this result.

unsigned getResultNumber() const

Returns the number of this result.

This class provides the API for ops that are known to be isolated from above.

This class provides the API for ops that are known to be terminators.

StringRef getStringRef() const

Return the name of this operation. This always succeeds.

void printAssembly(Operation *op, OpAsmPrinter &p, StringRef defaultDialect) const

This hook implements the AsmPrinter for this operation.

void print(raw_ostream &os) const

Operation is the basic unit of execution within MLIR.

bool use_empty()

Returns true if this operation has no uses.

bool hasTrait()

Returns true if the operation was registered with a particular trait, e.g.

Dialect * getDialect()

Return the dialect this operation is associated with, or nullptr if the associated dialect is not loa...

unsigned getNumSuccessors()

OpResult getResult(unsigned idx)

Get the 'idx'th result of this operation.

void print(raw_ostream &os, const OpPrintingFlags &flags=std::nullopt)

MLIRContext * getContext()

Return the context this operation is associated with.

std::optional< RegisteredOperationName > getRegisteredInfo()

If this operation has a registered operation description, return it.

Location getLoc()

The source location the operation was defined or derived from.

unsigned getNumOperands()

Attribute getPropertiesAsAttribute()

Return the properties converted to an attribute.

Operation * getParentOp()

Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...

ArrayRef< NamedAttribute > getAttrs()

Return all of the attributes on this operation.

MutableArrayRef< Region > getRegions()

Returns the regions held by this operation.

OperationName getName()

The name of an operation is the key identifier for it.

operand_type_range getOperandTypes()

result_type_range getResultTypes()

LLVM_DUMP_METHOD void dumpPretty()

operand_range getOperands()

Returns an iterator on the underlying Value's.

user_range getUsers()

Returns a range of all users.

SuccessorRange getSuccessors()

result_range getResults()

unsigned getNumResults()

Return the number of results held by this operation.

This class contains a list of basic blocks and a link to the parent operation it is attached to.

iterator_range< OpIterator > getOps()

BlockArgListType getArguments()

Operation * getParentOp()

Return the parent operation this region is attached to.

unsigned getNumArguments()

BlockArgument getArgument(unsigned i)

This diagnostic handler is a simple RAII class that registers and erases a diagnostic handler on a gi...

Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...

const void * getAsOpaquePointer() const

Methods for supporting PointerLikeTypeTraits.

Dialect & getDialect() const

Get the dialect this type is registered to.

static Type getFromOpaquePointer(const void *pointer)

void walkImmediateSubElements(function_ref< void(Attribute)> walkAttrsFn, function_ref< void(Type)> walkTypesFn) const

Walk all of the immediately nested sub-attributes and sub-types.

This class provides an abstraction over the different types of ranges over Values.

This class represents an instance of an SSA value in the MLIR system, representing a computable value...

bool use_empty() const

Returns true if this value has no uses.

void print(raw_ostream &os) const

Type getType() const

Return the type of this value.

void printAsOperand(raw_ostream &os, AsmState &state) const

Print this value as if it were an operand.

user_range getUsers() const

Location getLoc() const

Return the location of this value.

Operation * getDefiningOp() const

If this value is the result of an operation, return the operation that defines it.

void registerOperationLocation(Operation *op, unsigned line, unsigned col)

Register the location, line and column, within the buffer that the given operation was printed at.

const OpPrintingFlags & getPrinterFlags() const

Get the printer flags.

auto getResourcePrinters()

Return the non-dialect resource printers.

LogicalResult pushCyclicPrinting(const void *opaquePointer)

SSANameState & getSSANameState()

Get the state used for SSA names.

DialectInterfaceCollection< OpAsmDialectInterface > & getDialectInterfaces()

Return the dialects within the context that implement OpAsmDialectInterface.

AliasState & getAliasState()

Get the state used for aliases.

void initializeAliases(Operation *op)

Initialize the alias state to enable the printing of aliases.

AsmStateImpl(Operation *op, const OpPrintingFlags &printerFlags, AsmState::LocationMap *locationMap)

DenseMap< Dialect *, SetVector< AsmDialectResourceHandle > > & getDialectResources()

Return the referenced dialect resources within the printer.

AsmStateImpl(MLIRContext *ctx, const OpPrintingFlags &printerFlags, AsmState::LocationMap *locationMap)

DistinctState & getDistinctState()

Get the state used for distinct attribute identifiers.

Base class for DenseArrayAttr that is instantiated and specialized for each supported element type be...

static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef< T > content)

Builder from ArrayRef.

void printType(Type type, AsmPrinter &printer)

Prints an LLVM Dialect type.

LogicalResult parseCommaSeparatedList(llvm:🆑:Option &opt, StringRef argName, StringRef optionStr, function_ref< LogicalResult(StringRef)> elementParseFn)

Parse a string containing a list of comma-delimited elements, invoking the given parser for each sub-...

void printDimensionList(raw_ostream &stream, Range &&shape)

constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)

bool operator<(const Fraction &x, const Fraction &y)

Include the generated interface declarations.

ParseResult parseDimensionList(OpAsmParser &parser, DenseI64ArrayAttr &dimensions)

StringRef toString(AsmResourceEntryKind kind)

Type getType(OpFoldResult ofr)

Returns the int type of the integer in ofr.

OpAsmAliasResult

Holds the result of OpAsm{Dialect,Attr,Type}Interface::getAlias hook call.

@ NoAlias

The object (type or attribute) is not supported by the hook and an alias was not provided.

@ CeilDiv

RHS of ceildiv is always a constant or a symbolic expression.

@ Mul

RHS of mul is always a constant or a symbolic expression.

@ Mod

RHS of mod is always a constant or a symbolic expression with a positive value.

@ DimId

Dimensional identifier.

@ FloorDiv

RHS of floordiv is always a constant or a symbolic expression.

@ Constant

Constant integer.

@ SymbolId

Symbolic identifier.

void registerAsmPrinterCLOptions()

Register a set of useful command-line options that can be used to configure various flags within the ...

Type parseType(llvm::StringRef typeStr, MLIRContext *context, size_t *numRead=nullptr, bool isKnownNullTerminated=false)

This parses a single MLIR type to an MLIR context if it was valid.

AsmResourceEntryKind

This enum represents the different kinds of resource values.

@ Blob

A blob of data with an accompanying alignment.

LogicalResult verify(Operation *op, bool verifyRecursively=true)

Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...

raw_ostream & operator<<(raw_ostream &os, const AliasResult &result)

Represents a range (offset, size, and stride) where each element of the triple may be dynamic or stat...

This trait is used to determine if a storage user, like Type, is mutable or not.