MLIR: lib/Bytecode/Reader/BytecodeReader.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

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

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

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

23#include "llvm/ADT/StringRef.h"

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

25#include "llvm/Support/MemoryBufferRef.h"

26#include "llvm/Support/SourceMgr.h"

27

28#include

29#include

30#include

31#include

32#include

33#include

34#include

35

36#define DEBUG_TYPE "mlir-bytecode-reader"

37

38using namespace mlir;

39

40

42 switch (sectionID) {

44 return "String (0)";

46 return "Dialect (1)";

48 return "AttrType (2)";

50 return "AttrTypeOffset (3)";

52 return "IR (4)";

54 return "Resource (5)";

56 return "ResourceOffset (6)";

58 return "DialectVersions (7)";

60 return "Properties (8)";

61 default:

62 return ("Unknown (" + Twine(static_cast<unsigned>(sectionID)) + ")").str();

63 }

64}

65

66

68 switch (sectionID) {

74 return false;

78 return true;

81 default:

82 llvm_unreachable("unknown section ID");

83 }

84}

85

86

87

88

89

90namespace {

91class EncodingReader {

92public:

93 explicit EncodingReader(ArrayRef<uint8_t> contents, Location fileLoc)

94 : buffer(contents), dataIt(buffer.begin()), fileLoc(fileLoc) {}

95 explicit EncodingReader(StringRef contents, Location fileLoc)

96 : EncodingReader({reinterpret_cast<const uint8_t *>(contents.data()),

97 contents.size()},

98 fileLoc) {}

99

100

101 bool empty() const { return dataIt == buffer.end(); }

102

103

104 size_t size() const { return buffer.end() - dataIt; }

105

106

107 LogicalResult alignTo(unsigned alignment) {

108 if (!llvm::isPowerOf2_32(alignment))

109 return emitError("expected alignment to be a power-of-two");

110

111 auto isUnaligned = [&](const uint8_t *ptr) {

112 return ((uintptr_t)ptr & (alignment - 1)) != 0;

113 };

114

115

116

117

118

119 while (isUnaligned(dataIt)) {

120 uint8_t padding;

121 if (failed(parseByte(padding)))

122 return failure();

124 return emitError("expected alignment byte (0xCB), but got: '0x" +

125 llvm::utohexstr(padding) + "'");

126 }

127 }

128

129

130

131 if (LLVM_UNLIKELY(isUnaligned(dataIt))) {

132 return emitError("expected data iterator aligned to ", alignment,

133 ", but got pointer: '0x" +

134 llvm::utohexstr((uintptr_t)dataIt) + "'");

135 }

136

138 }

139

140

141 template <typename... Args>

142 InFlightDiagnostic emitError(Args &&...args) const {

143 return ::emitError(fileLoc).append(std::forward(args)...);

144 }

145 InFlightDiagnostic emitError() const { return ::emitError(fileLoc); }

146

147

148 template

149 LogicalResult parseByte(T &value) {

150 if (empty())

151 return emitError("attempting to parse a byte at the end of the bytecode");

152 value = static_cast<T>(*dataIt++);

154 }

155

156 LogicalResult parseBytes(size_t length, ArrayRef<uint8_t> &result) {

157 if (length > size()) {

158 return emitError("attempting to parse ", length, " bytes when only ",

159 size(), " remain");

160 }

161 result = {dataIt, length};

162 dataIt += length;

164 }

165

166

167 LogicalResult parseBytes(size_t length, uint8_t *result) {

168 if (length > size()) {

169 return emitError("attempting to parse ", length, " bytes when only ",

170 size(), " remain");

171 }

172 memcpy(result, dataIt, length);

173 dataIt += length;

175 }

176

177

178

179 LogicalResult parseBlobAndAlignment(ArrayRef<uint8_t> &data,

180 uint64_t &alignment) {

181 uint64_t dataSize;

182 if (failed(parseVarInt(alignment)) || failed(parseVarInt(dataSize)) ||

183 failed(alignTo(alignment)))

184 return failure();

185 return parseBytes(dataSize, data);

186 }

187

188

189

190

191

192

193

194

195 LogicalResult parseVarInt(uint64_t &result) {

196

198 return failure();

199

200

201

202 if (LLVM_LIKELY(result & 1)) {

205 }

206

207

208

209

210 if (LLVM_UNLIKELY(result == 0)) {

211 llvm::support::ulittle64_t resultLE;

212 if (failed(parseBytes(sizeof(resultLE),

213 reinterpret_cast<uint8_t *>(&resultLE))))

214 return failure();

217 }

218 return parseMultiByteVarInt(result);

219 }

220

221

222

223

224 LogicalResult parseSignedVarInt(uint64_t &result) {

226 return failure();

227

230 }

231

232

233

234 LogicalResult parseVarIntWithFlag(uint64_t &result, bool &flag) {

236 return failure();

240 }

241

242

243 LogicalResult skipBytes(size_t length) {

244 if (length > size()) {

245 return emitError("attempting to skip ", length, " bytes when only ",

246 size(), " remain");

247 }

248 dataIt += length;

250 }

251

252

253

254 LogicalResult parseNullTerminatedString(StringRef &result) {

255 const char *startIt = (const char *)dataIt;

256 const char *nulIt = (const char *)memchr(startIt, 0, size());

257 if (!nulIt)

259 "malformed null-terminated string, no null character found");

260

261 result = StringRef(startIt, nulIt - startIt);

262 dataIt = (const uint8_t *)nulIt + 1;

264 }

265

266

267 using ValidateAlignmentFn = function_ref<LogicalResult(unsigned alignment)>;

268

269

270

272 ValidateAlignmentFn alignmentValidator,

273 ArrayRef<uint8_t> &sectionData) {

274 uint8_t sectionIDAndHasAlignment;

275 uint64_t length;

276 if (failed(parseByte(sectionIDAndHasAlignment)) ||

277 failed(parseVarInt(length)))

278 return failure();

279

280

281

283 0b01111111);

284 bool hasAlignment = sectionIDAndHasAlignment & 0b10000000;

285

286

287

289 return emitError("invalid section ID: ", unsigned(sectionID));

290

291

292 if (hasAlignment) {

293

294 uint64_t alignment;

295 if (failed(parseVarInt(alignment)))

296 return failure();

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330 if (failed(alignmentValidator(alignment)))

331 return emitError("failed to align section ID: ", unsigned(sectionID));

332

333

334 if (failed(alignTo(alignment)))

335 return failure();

336 }

337

338

339 return parseBytes(static_cast<size_t>(length), sectionData);

340 }

341

342 Location getLoc() const { return fileLoc; }

343

344private:

345

346

347

348

349

350

351 LLVM_ATTRIBUTE_NOINLINE LogicalResult parseMultiByteVarInt(uint64_t &result) {

352

353

354

355

356

357 uint32_t numBytes = llvm::countr_zero<uint32_t>(result);

358 assert(numBytes > 0 && numBytes <= 7 &&

359 "unexpected number of trailing zeros in varint encoding");

360

361

362 llvm::support::ulittle64_t resultLE(result);

364 parseBytes(numBytes, reinterpret_cast<uint8_t *>(&resultLE) + 1)))

365 return failure();

366

367

368

369 result = resultLE >> (numBytes + 1);

371 }

372

373

374 ArrayRef<uint8_t> buffer;

375

376

377 const uint8_t *dataIt;

378

379

380 Location fileLoc;

381};

382}

383

384

385

386

387

388template <typename RangeT, typename T>

389static LogicalResult resolveEntry(EncodingReader &reader, RangeT &entries,

390 uint64_t index, T &entry,

391 StringRef entryStr) {

392 if (index >= entries.size())

393 return reader.emitError("invalid ", entryStr, " index: ", index);

394

395

396 if constexpr (std::is_convertible_v<llvm::detail::ValueOfRange, T>)

397 entry = entries[index];

398 else

399 entry = &entries[index];

401}

402

403

404template <typename RangeT, typename T>

405static LogicalResult parseEntry(EncodingReader &reader, RangeT &entries,

406 T &entry, StringRef entryStr) {

407 uint64_t entryIdx;

408 if (failed(reader.parseVarInt(entryIdx)))

409 return failure();

410 return resolveEntry(reader, entries, entryIdx, entry, entryStr);

411}

412

413

414

415

416

417namespace {

418

419

420class StringSectionReader {

421public:

422

423 LogicalResult initialize(Location fileLoc, ArrayRef<uint8_t> sectionData);

424

425

426

427 LogicalResult parseString(EncodingReader &reader, StringRef &result) const {

429 }

430

431

432

433

434 LogicalResult parseStringWithFlag(EncodingReader &reader, StringRef &result,

435 bool &flag) const {

436 uint64_t entryIdx;

437 if (failed(reader.parseVarIntWithFlag(entryIdx, flag)))

438 return failure();

439 return parseStringAtIndex(reader, entryIdx, result);

440 }

441

442

443

444 LogicalResult parseStringAtIndex(EncodingReader &reader, uint64_t index,

445 StringRef &result) const {

447 }

448

449private:

450

451 SmallVector strings;

452};

453}

454

455LogicalResult StringSectionReader::initialize(Location fileLoc,

457 EncodingReader stringReader(sectionData, fileLoc);

458

459

460 uint64_t numStrings;

461 if (failed(stringReader.parseVarInt(numStrings)))

462 return failure();

463 strings.resize(numStrings);

464

465

466

467 size_t stringDataEndOffset = sectionData.size();

468 for (StringRef &string : llvm::reverse(strings)) {

469 uint64_t stringSize;

470 if (failed(stringReader.parseVarInt(stringSize)))

471 return failure();

472 if (stringDataEndOffset < stringSize) {

473 return stringReader.emitError(

474 "string size exceeds the available data size");

475 }

476

477

478 size_t stringOffset = stringDataEndOffset - stringSize;

479 string = StringRef(

480 reinterpret_cast<const char *>(sectionData.data() + stringOffset),

481 stringSize - 1);

482 stringDataEndOffset = stringOffset;

483 }

484

485

486

487 if ((sectionData.size() - stringReader.size()) != stringDataEndOffset) {

488 return stringReader.emitError("unexpected trailing data between the "

489 "offsets for strings and their data");

490 }

492}

493

494

495

496

497

498namespace {

499class DialectReader;

500

501

502struct BytecodeDialect {

503

504

505

506

507 LogicalResult load(const DialectReader &reader, MLIRContext *ctx);

508

509

510

511 Dialect *getLoadedDialect() const {

512 assert(dialect &&

513 "expected `load` to be invoked before `getLoadedDialect`");

514 return *dialect;

515 }

516

517

518

519

520 std::optional<Dialect *> dialect;

521

522

523

524

525 const BytecodeDialectInterface *interface = nullptr;

526

527

528 StringRef name;

529

530

531 ArrayRef<uint8_t> versionBuffer;

532

533

534 std::unique_ptr loadedVersion;

535};

536

537

538struct BytecodeOperationName {

539 BytecodeOperationName(BytecodeDialect *dialect, StringRef name,

540 std::optional wasRegistered)

541 : dialect(dialect), name(name), wasRegistered(wasRegistered) {}

542

543

544

545 std::optional opName;

546

547

548 BytecodeDialect *dialect;

549

550

551 StringRef name;

552

553

554

555 std::optional wasRegistered;

556};

557}

558

559

561 EncodingReader &reader,

562 MutableArrayRef<std::unique_ptr> dialects,

563 function_ref<LogicalResult(BytecodeDialect *)> entryCallback) {

564

565 std::unique_ptr *dialect;

566 if (failed(parseEntry(reader, dialects, dialect, "dialect")))

567 return failure();

568 uint64_t numEntries;

569 if (failed(reader.parseVarInt(numEntries)))

570 return failure();

571

572 for (uint64_t i = 0; i < numEntries; ++i)

573 if (failed(entryCallback(dialect->get())))

574 return failure();

576}

577

578

579

580

581

582namespace {

583

584class ResourceSectionReader {

585public:

586

587 LogicalResult

589 MutableArrayRef<std::unique_ptr> dialects,

590 StringSectionReader &stringReader, ArrayRef<uint8_t> sectionData,

591 ArrayRef<uint8_t> offsetSectionData, DialectReader &dialectReader,

592 const std::shared_ptrllvm::SourceMgr &bufferOwnerRef);

593

594

595 LogicalResult parseResourceHandle(EncodingReader &reader,

596 AsmDialectResourceHandle &result) const {

597 return parseEntry(reader, dialectResources, result, "resource handle");

598 }

599

600private:

601

602 SmallVector dialectResources;

603 llvm::StringMapstd::string dialectResourceHandleRenamingMap;

604};

605

606class ParsedResourceEntry : public AsmParsedResourceEntry {

607public:

609 EncodingReader &reader, StringSectionReader &stringReader,

610 const std::shared_ptrllvm::SourceMgr &bufferOwnerRef)

611 : key(key), kind(kind), reader(reader), stringReader(stringReader),

612 bufferOwnerRef(bufferOwnerRef) {}

613 ~ParsedResourceEntry() override = default;

614

615 StringRef getKey() const final { return key; }

616

617 InFlightDiagnostic emitError() const final { return reader.emitError(); }

618

620

621 FailureOr parseAsBool() const final {

622 if (kind != AsmResourceEntryKind::Bool)

623 return emitError() << "expected a bool resource entry, but found a "

624 << toString(kind) << " entry instead";

625

626 bool value;

627 if (failed(reader.parseByte(value)))

628 return failure();

629 return value;

630 }

631 FailureOrstd::string parseAsString() const final {

632 if (kind != AsmResourceEntryKind::String)

633 return emitError() << "expected a string resource entry, but found a "

634 << toString(kind) << " entry instead";

635

636 StringRef string;

637 if (failed(stringReader.parseString(reader, string)))

638 return failure();

639 return string.str();

640 }

641

642 FailureOr

643 parseAsBlob(BlobAllocatorFn allocator) const final {

644 if (kind != AsmResourceEntryKind::Blob)

645 return emitError() << "expected a blob resource entry, but found a "

646 << toString(kind) << " entry instead";

647

648 ArrayRef<uint8_t> data;

649 uint64_t alignment;

650 if (failed(reader.parseBlobAndAlignment(data, alignment)))

651 return failure();

652

653

654

655 if (bufferOwnerRef) {

656 ArrayRef charData(reinterpret_cast<const char *>(data.data()),

657 data.size());

658

659

660

661

663 charData, alignment,

664 [bufferOwnerRef = bufferOwnerRef](void *, size_t, size_t) {});

665 }

666

667

668

669 AsmResourceBlob blob = allocator(data.size(), alignment);

670 assert(llvm::isAddrAligned(llvm::Align(alignment), blob.getData().data()) &&

672 "blob allocator did not return a properly aligned address");

673 memcpy(blob.getMutableData().data(), data.data(), data.size());

674 return blob;

675 }

676

677private:

678 StringRef key;

680 EncodingReader &reader;

681 StringSectionReader &stringReader;

682 const std::shared_ptrllvm::SourceMgr &bufferOwnerRef;

683};

684}

685

686template

687static LogicalResult

689 EncodingReader &offsetReader, EncodingReader &resourceReader,

690 StringSectionReader &stringReader, T *handler,

691 const std::shared_ptrllvm::SourceMgr &bufferOwnerRef,

692 function_ref<StringRef(StringRef)> remapKey = {},

693 function_ref<LogicalResult(StringRef)> processKeyFn = {}) {

694 uint64_t numResources;

695 if (failed(offsetReader.parseVarInt(numResources)))

696 return failure();

697

698 for (uint64_t i = 0; i < numResources; ++i) {

699 StringRef key;

701 uint64_t resourceOffset;

702 ArrayRef<uint8_t> data;

703 if (failed(stringReader.parseString(offsetReader, key)) ||

704 failed(offsetReader.parseVarInt(resourceOffset)) ||

705 failed(offsetReader.parseByte(kind)) ||

706 failed(resourceReader.parseBytes(resourceOffset, data)))

707 return failure();

708

709

710 if ((processKeyFn && failed(processKeyFn(key))))

711 return failure();

712

713

714

715 if (allowEmpty && data.empty())

716 continue;

717

718

719 if (!handler)

720 continue;

721

722

723 EncodingReader entryReader(data, fileLoc);

724 key = remapKey(key);

725 ParsedResourceEntry entry(key, kind, entryReader, stringReader,

726 bufferOwnerRef);

727 if (failed(handler->parseResource(entry)))

728 return failure();

729 if (!entryReader.empty()) {

730 return entryReader.emitError(

731 "unexpected trailing bytes in resource entry '", key, "'");

732 }

733 }

735}

736

737LogicalResult ResourceSectionReader::initialize(

738 Location fileLoc, const ParserConfig &config,

739 MutableArrayRef<std::unique_ptr> dialects,

740 StringSectionReader &stringReader, ArrayRef<uint8_t> sectionData,

741 ArrayRef<uint8_t> offsetSectionData, DialectReader &dialectReader,

742 const std::shared_ptrllvm::SourceMgr &bufferOwnerRef) {

743 EncodingReader resourceReader(sectionData, fileLoc);

744 EncodingReader offsetReader(offsetSectionData, fileLoc);

745

746

747 uint64_t numExternalResourceGroups;

748 if (failed(offsetReader.parseVarInt(numExternalResourceGroups)))

749 return failure();

750

751

752

753 auto parseGroup = [&](auto *handler, bool allowEmpty = false,

754 function_ref<LogicalResult(StringRef)> keyFn = {}) {

755 auto resolveKey = [&](StringRef key) -> StringRef {

756 auto it = dialectResourceHandleRenamingMap.find(key);

757 if (it == dialectResourceHandleRenamingMap.end())

758 return key;

759 return it->second;

760 };

761

762 return parseResourceGroup(fileLoc, allowEmpty, offsetReader, resourceReader,

763 stringReader, handler, bufferOwnerRef, resolveKey,

764 keyFn);

765 };

766

767

768 for (uint64_t i = 0; i < numExternalResourceGroups; ++i) {

769 StringRef key;

770 if (failed(stringReader.parseString(offsetReader, key)))

771 return failure();

772

773

774

775 AsmResourceParser *handler = config.getResourceParser(key);

776 if (!handler) {

777 emitWarning(fileLoc) << "ignoring unknown external resources for '" << key

778 << "'";

779 }

780

781 if (failed(parseGroup(handler)))

782 return failure();

783 }

784

785

786 MLIRContext *ctx = fileLoc->getContext();

787 while (!offsetReader.empty()) {

788 std::unique_ptr *dialect;

789 if (failed(parseEntry(offsetReader, dialects, dialect, "dialect")) ||

790 failed((*dialect)->load(dialectReader, ctx)))

791 return failure();

792 Dialect *loadedDialect = (*dialect)->getLoadedDialect();

793 if (!loadedDialect) {

794 return resourceReader.emitError()

795 << "dialect '" << (*dialect)->name << "' is unknown";

796 }

797 const auto *handler = dyn_cast(loadedDialect);

798 if (!handler) {

799 return resourceReader.emitError()

800 << "unexpected resources for dialect '" << (*dialect)->name << "'";

801 }

802

803

804 auto processResourceKeyFn = [&](StringRef key) -> LogicalResult {

805 FailureOr handle =

806 handler->declareResource(key);

807 if (failed(handle)) {

808 return resourceReader.emitError()

809 << "unknown 'resource' key '" << key << "' for dialect '"

810 << (*dialect)->name << "'";

811 }

812 dialectResourceHandleRenamingMap[key] = handler->getResourceKey(*handle);

813 dialectResources.push_back(*handle);

815 };

816

817

818

819 if (failed(parseGroup(handler, true, processResourceKeyFn)))

820 return failure();

821 }

822

824}

825

826

827

828

829

830namespace {

831

832

833

834

835

836

837

838

839

840

841

842

843

844

845

846

847

848

849

850

851class AttrTypeReader {

852

853 template

854 struct Entry {

855

856 T entry = {};

857

858 BytecodeDialect *dialect = nullptr;

859

860

861 bool hasCustomEncoding = false;

862

863 ArrayRef<uint8_t> data;

864 };

865 using AttrEntry = Entry;

866 using TypeEntry = Entry;

867

868public:

869 AttrTypeReader(const StringSectionReader &stringReader,

870 const ResourceSectionReader &resourceReader,

871 const llvm::StringMap<BytecodeDialect *> &dialectsMap,

872 uint64_t &bytecodeVersion, Location fileLoc,

873 const ParserConfig &config)

874 : stringReader(stringReader), resourceReader(resourceReader),

875 dialectsMap(dialectsMap), fileLoc(fileLoc),

876 bytecodeVersion(bytecodeVersion), parserConfig(config) {}

877

878

879 LogicalResult

880 initialize(MutableArrayRef<std::unique_ptr> dialects,

881 ArrayRef<uint8_t> sectionData,

882 ArrayRef<uint8_t> offsetSectionData);

883

884 LogicalResult readAttribute(uint64_t index, Attribute &result,

885 uint64_t depth = 0) {

886 return readEntry(attributes, index, result, "attribute", depth);

887 }

888

889 LogicalResult readType(uint64_t index, Type &result, uint64_t depth = 0) {

890 return readEntry(types, index, result, "type", depth);

891 }

892

893

894

895 Attribute resolveAttribute(size_t index, uint64_t depth = 0) {

896 return resolveEntry(attributes, index, "Attribute", depth);

897 }

898 Type resolveType(size_t index, uint64_t depth = 0) {

899 return resolveEntry(types, index, "Type", depth);

900 }

901

902 Attribute getAttributeOrSentinel(size_t index) {

903 if (index >= attributes.size())

904 return nullptr;

905 return attributes[index].entry;

906 }

907 Type getTypeOrSentinel(size_t index) {

908 if (index >= types.size())

909 return nullptr;

910 return types[index].entry;

911 }

912

913

915 uint64_t attrIdx;

916 if (failed(reader.parseVarInt(attrIdx)))

917 return failure();

918 result = resolveAttribute(attrIdx);

920 }

921 LogicalResult parseOptionalAttribute(EncodingReader &reader,

923 uint64_t attrIdx;

924 bool flag;

925 if (failed(reader.parseVarIntWithFlag(attrIdx, flag)))

926 return failure();

927 if (!flag)

929 result = resolveAttribute(attrIdx);

931 }

932

933 LogicalResult parseType(EncodingReader &reader, Type &result) {

934 uint64_t typeIdx;

935 if (failed(reader.parseVarInt(typeIdx)))

936 return failure();

937 result = resolveType(typeIdx);

939 }

940

941 template

943 Attribute baseResult;

945 return failure();

946 if ((result = dyn_cast(baseResult)))

948 return reader.emitError("expected attribute of type: ",

949 llvm::getTypeName(), ", but got: ", baseResult);

950 }

951

952

953 void addDeferredParsing(uint64_t index) { deferredWorklist.push_back(index); }

954

955private:

956

957 template

958 T resolveEntry(SmallVectorImpl<Entry> &entries, uint64_t index,

959 StringRef entryType, uint64_t depth = 0);

960

961

962

963 template

964 LogicalResult readEntry(SmallVectorImpl<Entry> &entries, uint64_t index,

965 T &result, StringRef entryType, uint64_t depth);

966

967

968

969 template

970 LogicalResult parseCustomEntry(Entry &entry, EncodingReader &reader,

971 StringRef entryType, uint64_t index,

972 uint64_t depth);

973

974

975

976 template

977 LogicalResult parseAsmEntry(T &result, EncodingReader &reader,

978 StringRef entryType);

979

980

981

982 const StringSectionReader &stringReader;

983

984

985

986 const ResourceSectionReader &resourceReader;

987

988

989

990 const llvm::StringMap<BytecodeDialect *> &dialectsMap;

991

992

993 SmallVector attributes;

994 SmallVector types;

995

996

997 Location fileLoc;

998

999

1000 uint64_t &bytecodeVersion;

1001

1002

1003 const ParserConfig &parserConfig;

1004

1005

1006

1007 std::vector<uint64_t> deferredWorklist;

1008};

1009

1010class DialectReader : public DialectBytecodeReader {

1011public:

1012 DialectReader(AttrTypeReader &attrTypeReader,

1013 const StringSectionReader &stringReader,

1014 const ResourceSectionReader &resourceReader,

1015 const llvm::StringMap<BytecodeDialect *> &dialectsMap,

1016 EncodingReader &reader, uint64_t &bytecodeVersion,

1017 uint64_t depth = 0)

1018 : attrTypeReader(attrTypeReader), stringReader(stringReader),

1019 resourceReader(resourceReader), dialectsMap(dialectsMap),

1020 reader(reader), bytecodeVersion(bytecodeVersion), depth(depth) {}

1021

1022 InFlightDiagnostic emitError(const Twine &msg) const override {

1023 return reader.emitError(msg);

1024 }

1025

1026 FailureOr<const DialectVersion *>

1027 getDialectVersion(StringRef dialectName) const override {

1028

1029 auto dialectEntry = dialectsMap.find(dialectName);

1030 if (dialectEntry == dialectsMap.end())

1031 return failure();

1032

1033

1034

1035 if (failed(dialectEntry->getValue()->load(*this, getLoc().getContext())) ||

1036 dialectEntry->getValue()->loadedVersion == nullptr)

1037 return failure();

1038 return dialectEntry->getValue()->loadedVersion.get();

1039 }

1040

1041 MLIRContext *getContext() const override { return getLoc().getContext(); }

1042

1043 uint64_t getBytecodeVersion() const override { return bytecodeVersion; }

1044

1045 DialectReader withEncodingReader(EncodingReader &encReader) const {

1046 return DialectReader(attrTypeReader, stringReader, resourceReader,

1047 dialectsMap, encReader, bytecodeVersion);

1048 }

1049

1050 Location getLoc() const { return reader.getLoc(); }

1051

1052

1053

1054

1055

1056

1057

1058 static constexpr uint64_t maxAttrTypeDepth = 5;

1059

1060 LogicalResult readAttribute(Attribute &result) override {

1061 uint64_t index;

1062 if (failed(reader.parseVarInt(index)))

1063 return failure();

1064 if (depth > maxAttrTypeDepth) {

1065 if (Attribute attr = attrTypeReader.getAttributeOrSentinel(index)) {

1068 }

1069 attrTypeReader.addDeferredParsing(index);

1070 return failure();

1071 }

1072 return attrTypeReader.readAttribute(index, result, depth + 1);

1073 }

1074 LogicalResult readOptionalAttribute(Attribute &result) override {

1075 return attrTypeReader.parseOptionalAttribute(reader, result);

1076 }

1077 LogicalResult readType(Type &result) override {

1078 uint64_t index;

1079 if (failed(reader.parseVarInt(index)))

1080 return failure();

1081 if (depth > maxAttrTypeDepth) {

1082 if (Type type = attrTypeReader.getTypeOrSentinel(index)) {

1085 }

1086 attrTypeReader.addDeferredParsing(index);

1087 return failure();

1088 }

1089 return attrTypeReader.readType(index, result, depth + 1);

1090 }

1091

1093 AsmDialectResourceHandle handle;

1094 if (failed(resourceReader.parseResourceHandle(reader, handle)))

1095 return failure();

1096 return handle;

1097 }

1098

1099

1100

1101

1102

1103 LogicalResult readVarInt(uint64_t &result) override {

1104 return reader.parseVarInt(result);

1105 }

1106

1107 LogicalResult readSignedVarInt(int64_t &result) override {

1108 uint64_t unsignedResult;

1109 if (failed(reader.parseSignedVarInt(unsignedResult)))

1110 return failure();

1111 result = static_cast<int64_t>(unsignedResult);

1113 }

1114

1115 FailureOr readAPIntWithKnownWidth(unsigned bitWidth) override {

1116

1117 if (bitWidth <= 8) {

1118 uint8_t value;

1119 if (failed(reader.parseByte(value)))

1120 return failure();

1121 return APInt(bitWidth, value);

1122 }

1123

1124

1125 if (bitWidth <= 64) {

1126 uint64_t value;

1127 if (failed(reader.parseSignedVarInt(value)))

1128 return failure();

1129 return APInt(bitWidth, value);

1130 }

1131

1132

1133

1134 uint64_t numActiveWords;

1135 if (failed(reader.parseVarInt(numActiveWords)))

1136 return failure();

1137 SmallVector<uint64_t, 4> words(numActiveWords);

1138 for (uint64_t i = 0; i < numActiveWords; ++i)

1139 if (failed(reader.parseSignedVarInt(words[i])))

1140 return failure();

1141 return APInt(bitWidth, words);

1142 }

1143

1144 FailureOr

1145 readAPFloatWithKnownSemantics(const llvm::fltSemantics &semantics) override {

1146 FailureOr intVal =

1147 readAPIntWithKnownWidth(APFloat::getSizeInBits(semantics));

1149 return failure();

1150 return APFloat(semantics, *intVal);

1151 }

1152

1153 LogicalResult readString(StringRef &result) override {

1154 return stringReader.parseString(reader, result);

1155 }

1156

1157 LogicalResult readBlob(ArrayRef &result) override {

1158 uint64_t dataSize;

1159 ArrayRef<uint8_t> data;

1160 if (failed(reader.parseVarInt(dataSize)) ||

1161 failed(reader.parseBytes(dataSize, data)))

1162 return failure();

1163 result = llvm::ArrayRef(reinterpret_cast<const char *>(data.data()),

1164 data.size());

1166 }

1167

1168 LogicalResult readBool(bool &result) override {

1169 return reader.parseByte(result);

1170 }

1171

1172private:

1173 AttrTypeReader &attrTypeReader;

1174 const StringSectionReader &stringReader;

1175 const ResourceSectionReader &resourceReader;

1176 const llvm::StringMap<BytecodeDialect *> &dialectsMap;

1177 EncodingReader &reader;

1178 uint64_t &bytecodeVersion;

1179 uint64_t depth;

1180};

1181

1182

1183class PropertiesSectionReader {

1184public:

1185

1186 LogicalResult initialize(Location fileLoc, ArrayRef<uint8_t> sectionData) {

1187 if (sectionData.empty())

1189 EncodingReader propReader(sectionData, fileLoc);

1190 uint64_t count;

1191 if (failed(propReader.parseVarInt(count)))

1192 return failure();

1193

1194 if (failed(propReader.parseBytes(propReader.size(), propertiesBuffers)))

1195 return failure();

1196

1197 EncodingReader offsetsReader(propertiesBuffers, fileLoc);

1198 offsetTable.reserve(count);

1199 for (auto idx : llvm::seq<int64_t>(0, count)) {

1200 (void)idx;

1201 offsetTable.push_back(propertiesBuffers.size() - offsetsReader.size());

1202 ArrayRef<uint8_t> rawProperties;

1203 uint64_t dataSize;

1204 if (failed(offsetsReader.parseVarInt(dataSize)) ||

1205 failed(offsetsReader.parseBytes(dataSize, rawProperties)))

1206 return failure();

1207 }

1208 if (!offsetsReader.empty())

1209 return offsetsReader.emitError()

1210 << "Broken properties section: didn't exhaust the offsets table";

1212 }

1213

1214 LogicalResult read(Location fileLoc, DialectReader &dialectReader,

1215 OperationName *opName, OperationState &opState) const {

1216 uint64_t propertiesIdx;

1217 if (failed(dialectReader.readVarInt(propertiesIdx)))

1218 return failure();

1219 if (propertiesIdx >= offsetTable.size())

1220 return dialectReader.emitError("Properties idx out-of-bound for ")

1222 size_t propertiesOffset = offsetTable[propertiesIdx];

1223 if (propertiesIdx >= propertiesBuffers.size())

1224 return dialectReader.emitError("Properties offset out-of-bound for ")

1226

1227

1228 ArrayRef rawProperties;

1229 {

1230

1231

1232 EncodingReader reader(propertiesBuffers.drop_front(propertiesOffset),

1233 fileLoc);

1234

1236 dialectReader.withEncodingReader(reader).readBlob(rawProperties)))

1237 return failure();

1238 }

1239

1240 EncodingReader reader(

1241 StringRef(rawProperties.begin(), rawProperties.size()), fileLoc);

1242 DialectReader propReader = dialectReader.withEncodingReader(reader);

1243

1244 auto *iface = opName->getInterface();

1245 if (iface)

1246 return iface->readProperties(propReader, opState);

1248 return propReader.emitError(

1249 "has properties but missing BytecodeOpInterface for ")

1251

1252 return propReader.readAttribute(opState.propertiesAttr);

1253 }

1254

1255private:

1256

1257 ArrayRef<uint8_t> propertiesBuffers;

1258

1259

1260 SmallVector<int64_t> offsetTable;

1261};

1262}

1263

1264LogicalResult AttrTypeReader::initialize(

1265 MutableArrayRef<std::unique_ptr> dialects,

1266 ArrayRef<uint8_t> sectionData, ArrayRef<uint8_t> offsetSectionData) {

1267 EncodingReader offsetReader(offsetSectionData, fileLoc);

1268

1269

1270 uint64_t numAttributes, numTypes;

1271 if (failed(offsetReader.parseVarInt(numAttributes)) ||

1272 failed(offsetReader.parseVarInt(numTypes)))

1273 return failure();

1274 attributes.resize(numAttributes);

1275 types.resize(numTypes);

1276

1277

1278

1279 uint64_t currentOffset = 0;

1280 auto parseEntries = [&](auto &&range) {

1281 size_t currentIndex = 0, endIndex = range.size();

1282

1283

1284 auto parseEntryFn = [&](BytecodeDialect *dialect) -> LogicalResult {

1285 auto &entry = range[currentIndex++];

1286

1287 uint64_t entrySize;

1288 if (failed(offsetReader.parseVarIntWithFlag(entrySize,

1289 entry.hasCustomEncoding)))

1290 return failure();

1291

1292

1293 if (currentOffset + entrySize > sectionData.size()) {

1294 return offsetReader.emitError(

1295 "Attribute or Type entry offset points past the end of section");

1296 }

1297

1298 entry.data = sectionData.slice(currentOffset, entrySize);

1299 entry.dialect = dialect;

1300 currentOffset += entrySize;

1302 };

1303 while (currentIndex != endIndex)

1305 return failure();

1307 };

1308

1309

1310 if (failed(parseEntries(attributes)) || failed(parseEntries(types)))

1311 return failure();

1312

1313

1314 if (!offsetReader.empty()) {

1315 return offsetReader.emitError(

1316 "unexpected trailing data in the Attribute/Type offset section");

1317 }

1318

1320}

1321

1322template

1323T AttrTypeReader::resolveEntry(SmallVectorImpl<Entry> &entries,

1324 uint64_t index, StringRef entryType,

1325 uint64_t depth) {

1326 if (index >= entries.size()) {

1327 emitError(fileLoc) << "invalid " << entryType << " index: " << index;

1328 return {};

1329 }

1330

1331

1332

1333 assert(deferredWorklist.empty());

1335 if (succeeded(readEntry(entries, index, result, entryType, depth))) {

1336 assert(deferredWorklist.empty());

1338 }

1339 if (deferredWorklist.empty()) {

1340

1341 return T();

1342 }

1343

1344

1345

1346

1347

1348

1349 std::deque<size_t> worklist;

1350 llvm::DenseSet<size_t> inWorklist;

1351

1352

1353 worklist.push_back(index);

1354 inWorklist.insert(index);

1355 for (uint64_t idx : llvm::reverse(deferredWorklist)) {

1356 if (inWorklist.insert(idx).second)

1357 worklist.push_front(idx);

1358 }

1359

1360 while (!worklist.empty()) {

1361 size_t currentIndex = worklist.front();

1362 worklist.pop_front();

1363

1364

1365 deferredWorklist.clear();

1366

1368 if (succeeded(readEntry(entries, currentIndex, result, entryType, depth))) {

1369 inWorklist.erase(currentIndex);

1370 continue;

1371 }

1372

1373 if (deferredWorklist.empty()) {

1374

1375 return T();

1376 }

1377

1378

1379 worklist.push_back(currentIndex);

1380

1381

1382 for (uint64_t idx : llvm::reverse(deferredWorklist)) {

1383 if (inWorklist.insert(idx).second)

1384 worklist.push_front(idx);

1385 }

1386 deferredWorklist.clear();

1387 }

1388 return entries[index].entry;

1389}

1390

1391template

1392LogicalResult AttrTypeReader::readEntry(SmallVectorImpl<Entry> &entries,

1393 uint64_t index, T &result,

1394 StringRef entryType, uint64_t depth) {

1395 if (index >= entries.size())

1396 return emitError(fileLoc) << "invalid " << entryType << " index: " << index;

1397

1398

1399 Entry &entry = entries[index];

1400 if (entry.entry) {

1401 result = entry.entry;

1403 }

1404

1405

1406 EncodingReader reader(entry.data, fileLoc);

1407 LogicalResult parseResult =

1408 entry.hasCustomEncoding

1409 ? parseCustomEntry(entry, reader, entryType, index, depth)

1410 : parseAsmEntry(entry.entry, reader, entryType);

1411 if (failed(parseResult))

1412 return failure();

1413

1414 if (!reader.empty())

1415 return reader.emitError("unexpected trailing bytes after " + entryType +

1416 " entry");

1417

1418 result = entry.entry;

1420}

1421

1422template

1423LogicalResult AttrTypeReader::parseCustomEntry(Entry &entry,

1424 EncodingReader &reader,

1425 StringRef entryType,

1426 uint64_t index, uint64_t depth) {

1427 DialectReader dialectReader(*this, stringReader, resourceReader, dialectsMap,

1428 reader, bytecodeVersion, depth);

1429 if (failed(entry.dialect->load(dialectReader, fileLoc.getContext())))

1430 return failure();

1431

1432 if constexpr (std::is_same_v<T, Type>) {

1433

1434 for (const auto &callback :

1437 callback->read(dialectReader, entry.dialect->name, entry.entry)))

1438 return failure();

1439

1440 if (!!entry.entry)

1442

1443

1444

1445 reader = EncodingReader(entry.data, reader.getLoc());

1446 }

1447 } else {

1448

1449 for (const auto &callback :

1452 callback->read(dialectReader, entry.dialect->name, entry.entry)))

1453 return failure();

1454

1455 if (!!entry.entry)

1457

1458

1459

1460 reader = EncodingReader(entry.data, reader.getLoc());

1461 }

1462 }

1463

1464

1465 if (!entry.dialect->interface) {

1466 return reader.emitError("dialect '", entry.dialect->name,

1467 "' does not implement the bytecode interface");

1468 }

1469

1470 if constexpr (std::is_same_v<T, Type>)

1471 entry.entry = entry.dialect->interface->readType(dialectReader);

1472 else

1473 entry.entry = entry.dialect->interface->readAttribute(dialectReader);

1474

1475 return success(!!entry.entry);

1476}

1477

1478template

1479LogicalResult AttrTypeReader::parseAsmEntry(T &result, EncodingReader &reader,

1480 StringRef entryType) {

1481 StringRef asmStr;

1482 if (failed(reader.parseNullTerminatedString(asmStr)))

1483 return failure();

1484

1485

1486 size_t numRead = 0;

1487 MLIRContext *context = fileLoc->getContext();

1488 if constexpr (std::is_same_v<T, Type>)

1490 ::parseType(asmStr, context, &numRead, true);

1491 else

1493 true);

1495 return failure();

1496

1497

1498 if (numRead != asmStr.size()) {

1499 return reader.emitError("trailing characters found after ", entryType,

1500 " assembly format: ", asmStr.drop_front(numRead));

1501 }

1503}

1504

1505

1506

1507

1508

1509

1511 struct RegionReadState;

1512 using LazyLoadableOpsInfo =

1513 std::list<std::pair<Operation *, RegionReadState>>;

1514 using LazyLoadableOpsMap =

1516

1517public:

1519 llvm::MemoryBufferRef buffer,

1520 const std::shared_ptrllvm::SourceMgr &bufferOwnerRef)

1521 : config(config), fileLoc(fileLoc), lazyLoading(lazyLoading),

1522 attrTypeReader(stringReader, resourceReader, dialectsMap, version,

1523 fileLoc, config),

1524

1525

1526 forwardRefOpState(UnknownLoc::get(config.getContext()),

1527 "builtin.unrealized_conversion_cast", ValueRange(),

1528 NoneType::get(config.getContext())),

1529 buffer(buffer), bufferOwnerRef(bufferOwnerRef) {}

1530

1531

1532 LogicalResult read(Block *block,

1534

1535

1537

1539

1540

1541

1542 LogicalResult

1545 this->lazyOpsCallback = lazyOpsCallback;

1546 auto resetlazyOpsCallback =

1547 llvm::make_scope_exit([&] { this->lazyOpsCallback = nullptr; });

1548 auto it = lazyLoadableOpsMap.find(op);

1549 assert(it != lazyLoadableOpsMap.end() &&

1550 "materialize called on non-materializable op");

1552 }

1553

1554

1556 while (!lazyLoadableOpsMap.empty()) {

1557 if (failed(materialize(lazyLoadableOpsMap.begin())))

1558 return failure();

1559 }

1561 }

1562

1563

1564

1565

1566

1568 while (!lazyLoadableOps.empty()) {

1569 Operation *op = lazyLoadableOps.begin()->first;

1570 if (shouldMaterialize(op)) {

1571 if (failed(materialize(lazyLoadableOpsMap.find(op))))

1572 return failure();

1573 continue;

1574 }

1577 lazyLoadableOps.pop_front();

1578 lazyLoadableOpsMap.erase(op);

1579 }

1581 }

1582

1583private:

1584 LogicalResult materialize(LazyLoadableOpsMap::iterator it) {

1585 assert(it != lazyLoadableOpsMap.end() &&

1586 "materialize called on non-materializable op");

1587 valueScopes.emplace_back();

1588 std::vector regionStack;

1589 regionStack.push_back(std::move(it->getSecond()->second));

1590 lazyLoadableOps.erase(it->getSecond());

1591 lazyLoadableOpsMap.erase(it);

1592

1593 while (!regionStack.empty())

1594 if (failed(parseRegions(regionStack, regionStack.back())))

1595 return failure();

1597 }

1598

1599 LogicalResult checkSectionAlignment(

1600 unsigned alignment,

1602

1603

1604

1605

1606

1607

1608

1609

1610 const bool isGloballyAligned =

1611 ((uintptr_t)buffer.getBufferStart() & (alignment - 1)) == 0;

1612

1613 if (!isGloballyAligned)

1614 return emitError("expected section alignment ")

1615 << alignment << " but bytecode buffer 0x"

1616 << Twine::utohexstr((uint64_t)buffer.getBufferStart())

1617 << " is not aligned";

1618

1620 };

1621

1622

1624

1625

1626 LogicalResult parseVersion(EncodingReader &reader);

1627

1628

1629

1630

1631 LogicalResult parseDialectSection(ArrayRef<uint8_t> sectionData);

1632

1633

1634

1635

1636 FailureOr parseOpName(EncodingReader &reader,

1637 std::optional &wasRegistered);

1638

1639

1640

1641

1642

1643 template

1645 return attrTypeReader.parseAttribute(reader, result);

1646 }

1647 LogicalResult parseType(EncodingReader &reader, Type &result) {

1648 return attrTypeReader.parseType(reader, result);

1649 }

1650

1651

1652

1653

1654 LogicalResult

1655 parseResourceSection(EncodingReader &reader,

1656 std::optional<ArrayRef<uint8_t>> resourceData,

1657 std::optional<ArrayRef<uint8_t>> resourceOffsetData);

1658

1659

1660

1661

1662

1663

1664 struct RegionReadState {

1665 RegionReadState(Operation *op, EncodingReader *reader,

1666 bool isIsolatedFromAbove)

1667 : RegionReadState(op->getRegions(), reader, isIsolatedFromAbove) {}

1668 RegionReadState(MutableArrayRef regions, EncodingReader *reader,

1669 bool isIsolatedFromAbove)

1670 : curRegion(regions.begin()), endRegion(regions.end()), reader(reader),

1671 isIsolatedFromAbove(isIsolatedFromAbove) {}

1672

1673

1674 MutableArrayRef::iterator curRegion, endRegion;

1675

1676

1677

1678

1679 EncodingReader *reader;

1680 std::unique_ptr owningReader;

1681

1682

1683 unsigned numValues = 0;

1684

1685

1686 SmallVector<Block *> curBlocks;

1688

1689

1690

1691 uint64_t numOpsRemaining = 0;

1692

1693

1694 bool isIsolatedFromAbove = false;

1695 };

1696

1697 LogicalResult parseIRSection(ArrayRef<uint8_t> sectionData, Block *block);

1698 LogicalResult parseRegions(std::vector &regionStack,

1699 RegionReadState &readState);

1700 FailureOr<Operation *> parseOpWithoutRegions(EncodingReader &reader,

1701 RegionReadState &readState,

1702 bool &isIsolatedFromAbove);

1703

1704 LogicalResult parseRegion(RegionReadState &readState);

1705 LogicalResult parseBlockHeader(EncodingReader &reader,

1706 RegionReadState &readState);

1707 LogicalResult parseBlockArguments(EncodingReader &reader, Block *block);

1708

1709

1710

1711

1712

1713

1714 Value parseOperand(EncodingReader &reader);

1715

1716

1717 LogicalResult defineValues(EncodingReader &reader, ValueRange values);

1718

1719

1720 Value createForwardRef();

1721

1722

1723

1724

1725

1726

1727

1728 struct UseListOrderStorage {

1729 UseListOrderStorage(bool isIndexPairEncoding,

1730 SmallVector<unsigned, 4> &&indices)

1732 isIndexPairEncoding(isIndexPairEncoding) {};

1733

1734

1735 SmallVector<unsigned, 4> indices;

1736

1737

1738

1739 bool isIndexPairEncoding;

1740 };

1741

1742

1743

1744

1745

1746

1747 using UseListMapT = DenseMap<unsigned, UseListOrderStorage>;

1748 FailureOr parseUseListOrderForRange(EncodingReader &reader,

1749 uint64_t rangeSize);

1750

1751

1752 LogicalResult sortUseListOrder(Value value);

1753

1754

1755

1756 LogicalResult processUseLists(Operation *topLevelOp);

1757

1758

1759

1760

1761

1762

1763 struct ValueScope {

1764

1765

1766 void push(RegionReadState &readState) {

1767 nextValueIDs.push_back(values.size());

1768 values.resize(values.size() + readState.numValues);

1769 }

1770

1771

1772

1773 void pop(RegionReadState &readState) {

1774 values.resize(values.size() - readState.numValues);

1775 nextValueIDs.pop_back();

1776 }

1777

1778

1779 std::vector values;

1780

1781

1782

1783 SmallVector<unsigned, 4> nextValueIDs;

1784 };

1785

1786

1787 const ParserConfig &config;

1788

1789

1790 Location fileLoc;

1791

1792

1793 bool lazyLoading;

1794

1795

1796

1797

1798 LazyLoadableOpsInfo lazyLoadableOps;

1799 LazyLoadableOpsMap lazyLoadableOpsMap;

1800 llvm::function_ref<bool(Operation *)> lazyOpsCallback;

1801

1802

1803 AttrTypeReader attrTypeReader;

1804

1805

1806 uint64_t version = 0;

1807

1808

1809 StringRef producer;

1810

1811

1812 SmallVector<std::unique_ptr> dialects;

1813 llvm::StringMap<BytecodeDialect *> dialectsMap;

1814 SmallVector opNames;

1815

1816

1817 ResourceSectionReader resourceReader;

1818

1819

1820

1821 DenseMap<void *, UseListOrderStorage> valueToUseListMap;

1822

1823

1824 StringSectionReader stringReader;

1825

1826

1827 PropertiesSectionReader propertiesReader;

1828

1829

1830 std::vector valueScopes;

1831

1832

1834

1835

1836

1837 Block forwardRefOps;

1838

1839

1840

1841 Block openForwardRefOps;

1842

1843

1844 OperationState forwardRefOpState;

1845

1846

1847 llvm::MemoryBufferRef buffer;

1848

1849

1850

1851 const std::shared_ptrllvm::SourceMgr &bufferOwnerRef;

1852};

1853

1856 EncodingReader reader(buffer.getBuffer(), fileLoc);

1857 this->lazyOpsCallback = lazyOpsCallback;

1858 auto resetlazyOpsCallback =

1859 llvm::make_scope_exit([&] { this->lazyOpsCallback = nullptr; });

1860

1861

1862 if (failed(reader.skipBytes(StringRef("ML\xefR").size())))

1863 return failure();

1864

1865 if (failed(parseVersion(reader)) ||

1866 failed(reader.parseNullTerminatedString(producer)))

1867 return failure();

1868

1869

1870

1872 diag.attachNote() << "in bytecode version " << version

1873 << " produced by: " << producer;

1874 return failure();

1875 });

1876

1877 const auto checkSectionAlignment = [&](unsigned alignment) {

1878 return this->checkSectionAlignment(

1879 alignment, [&](const auto &msg) { return reader.emitError(msg); });

1880 };

1881

1882

1883 std::optional<ArrayRef<uint8_t>>

1885 while (!reader.empty()) {

1886

1889 if (failed(

1890 reader.parseSection(sectionID, checkSectionAlignment, sectionData)))

1891 return failure();

1892

1893

1894 if (sectionDatas[sectionID]) {

1895 return reader.emitError("duplicate top-level section: ",

1897 }

1898 sectionDatas[sectionID] = sectionData;

1899 }

1900

1903 if (!sectionDatas[i] && isSectionOptional(sectionID, version)) {

1904 return reader.emitError("missing data for top-level section: ",

1906 }

1907 }

1908

1909

1910 if (failed(stringReader.initialize(

1912 return failure();

1913

1914

1916 failed(propertiesReader.initialize(

1918 return failure();

1919

1920

1922 return failure();

1923

1924

1925 if (failed(parseResourceSection(

1928 return failure();

1929

1930

1931 if (failed(attrTypeReader.initialize(

1934 return failure();

1935

1936

1938}

1939

1940LogicalResult BytecodeReader::Impl::parseVersion(EncodingReader &reader) {

1941 if (failed(reader.parseVarInt(version)))

1942 return failure();

1943

1944

1947 if (version < minSupportedVersion) {

1948 return reader.emitError("bytecode version ", version,

1949 " is older than the current version of ",

1950 currentVersion, ", and upgrade is not supported");

1951 }

1952 if (version > currentVersion) {

1953 return reader.emitError("bytecode version ", version,

1954 " is newer than the current version ",

1955 currentVersion);

1956 }

1957

1959 lazyLoading = false;

1961}

1962

1963

1964

1965

1966

1967LogicalResult BytecodeDialect::load(const DialectReader &reader,

1968 MLIRContext *ctx) {

1969 if (dialect)

1973 return reader.emitError("dialect '")

1974 << name

1975 << "' is unknown. If this is intended, please call "

1976 "allowUnregisteredDialects() on the MLIRContext, or use "

1977 "-allow-unregistered-dialect with the MLIR tool used.";

1978 }

1979 dialect = loadedDialect;

1980

1981

1982

1983 if (loadedDialect)

1984 interface = dyn_cast(loadedDialect);

1985 if (!versionBuffer.empty()) {

1986 if (!interface)

1987 return reader.emitError("dialect '")

1988 << name

1989 << "' does not implement the bytecode interface, "

1990 "but found a version entry";

1991 EncodingReader encReader(versionBuffer, reader.getLoc());

1992 DialectReader versionReader = reader.withEncodingReader(encReader);

1993 loadedVersion = interface->readVersion(versionReader);

1994 if (!loadedVersion)

1995 return failure();

1996 }

1998}

1999

2000LogicalResult

2001BytecodeReader::Impl::parseDialectSection(ArrayRef<uint8_t> sectionData) {

2002 EncodingReader sectionReader(sectionData, fileLoc);

2003

2004

2005 uint64_t numDialects;

2006 if (failed(sectionReader.parseVarInt(numDialects)))

2007 return failure();

2008 dialects.resize(numDialects);

2009

2010 const auto checkSectionAlignment = [&](unsigned alignment) {

2011 return this->checkSectionAlignment(alignment, [&](const auto &msg) {

2012 return sectionReader.emitError(msg);

2013 });

2014 };

2015

2016

2017 for (uint64_t i = 0; i < numDialects; ++i) {

2018 dialects[i] = std::make_unique();

2019

2020

2022 if (failed(stringReader.parseString(sectionReader, dialects[i]->name)))

2023 return failure();

2024 continue;

2025 }

2026

2027

2028 uint64_t dialectNameIdx;

2029 bool versionAvailable;

2030 if (failed(sectionReader.parseVarIntWithFlag(dialectNameIdx,

2031 versionAvailable)))

2032 return failure();

2033 if (failed(stringReader.parseStringAtIndex(sectionReader, dialectNameIdx,

2034 dialects[i]->name)))

2035 return failure();

2036 if (versionAvailable) {

2038 if (failed(sectionReader.parseSection(sectionID, checkSectionAlignment,

2039 dialects[i]->versionBuffer)))

2040 return failure();

2042 emitError(fileLoc, "expected dialect version section");

2043 return failure();

2044 }

2045 }

2046 dialectsMap[dialects[i]->name] = dialects[i].get();

2047 }

2048

2049

2050 auto parseOpName = [&](BytecodeDialect *dialect) {

2051 StringRef opName;

2052 std::optional wasRegistered;

2053

2054

2056 if (failed(stringReader.parseString(sectionReader, opName)))

2057 return failure();

2058 } else {

2059 bool wasRegisteredFlag;

2060 if (failed(stringReader.parseStringWithFlag(sectionReader, opName,

2061 wasRegisteredFlag)))

2062 return failure();

2063 wasRegistered = wasRegisteredFlag;

2064 }

2065 opNames.emplace_back(dialect, opName, wasRegistered);

2067 };

2068

2069

2071 uint64_t numOps;

2072 if (failed(sectionReader.parseVarInt(numOps)))

2073 return failure();

2074 opNames.reserve(numOps);

2075 }

2076 while (!sectionReader.empty())

2078 return failure();

2080}

2081

2082FailureOr

2083BytecodeReader::Impl::parseOpName(EncodingReader &reader,

2084 std::optional &wasRegistered) {

2085 BytecodeOperationName *opName = nullptr;

2086 if (failed(parseEntry(reader, opNames, opName, "operation name")))

2087 return failure();

2088 wasRegistered = opName->wasRegistered;

2089

2090

2091 if (!opName->opName) {

2092

2093

2094

2095

2096 if (opName->name.empty()) {

2097 opName->opName.emplace(opName->dialect->name, getContext());

2098 } else {

2099

2100 DialectReader dialectReader(attrTypeReader, stringReader, resourceReader,

2101 dialectsMap, reader, version);

2102 if (failed(opName->dialect->load(dialectReader, getContext())))

2103 return failure();

2104 opName->opName.emplace((opName->dialect->name + "." + opName->name).str(),

2106 }

2107 }

2108 return *opName->opName;

2109}

2110

2111

2112

2113

2114

2115LogicalResult BytecodeReader::Impl::parseResourceSection(

2116 EncodingReader &reader, std::optional<ArrayRef<uint8_t>> resourceData,

2117 std::optional<ArrayRef<uint8_t>> resourceOffsetData) {

2118

2119 if (resourceData.has_value() != resourceOffsetData.has_value()) {

2120 if (resourceOffsetData)

2121 return emitError(fileLoc, "unexpected resource offset section when "

2122 "resource section is not present");

2124 fileLoc,

2125 "expected resource offset section when resource section is present");

2126 }

2127

2128

2129 if (!resourceData)

2131

2132

2133 DialectReader dialectReader(attrTypeReader, stringReader, resourceReader,

2134 dialectsMap, reader, version);

2135 return resourceReader.initialize(fileLoc, config, dialects, stringReader,

2136 *resourceData, *resourceOffsetData,

2137 dialectReader, bufferOwnerRef);

2138}

2139

2140

2141

2142

2143

2144FailureOrBytecodeReader::Impl::UseListMapT

2145BytecodeReader::Impl::parseUseListOrderForRange(EncodingReader &reader,

2146 uint64_t numResults) {

2147 BytecodeReader::Impl::UseListMapT map;

2148 uint64_t numValuesToRead = 1;

2149 if (numResults > 1 && failed(reader.parseVarInt(numValuesToRead)))

2150 return failure();

2151

2152 for (size_t valueIdx = 0; valueIdx < numValuesToRead; valueIdx++) {

2153 uint64_t resultIdx = 0;

2154 if (numResults > 1 && failed(reader.parseVarInt(resultIdx)))

2155 return failure();

2156

2157 uint64_t numValues;

2158 bool indexPairEncoding;

2159 if (failed(reader.parseVarIntWithFlag(numValues, indexPairEncoding)))

2160 return failure();

2161

2162 SmallVector<unsigned, 4> useListOrders;

2163 for (size_t idx = 0; idx < numValues; idx++) {

2164 uint64_t index;

2165 if (failed(reader.parseVarInt(index)))

2166 return failure();

2167 useListOrders.push_back(index);

2168 }

2169

2170

2171 map.try_emplace(resultIdx, UseListOrderStorage(indexPairEncoding,

2172 std::move(useListOrders)));

2173 }

2174

2175 return map;

2176}

2177

2178

2179

2180

2181

2182

2183LogicalResult BytecodeReader::Impl::sortUseListOrder(Value value) {

2184

2187

2188 bool hasIncomingOrder =

2190

2191

2192

2193 bool alreadySorted = true;

2194 auto &firstUse = *value.use_begin();

2195 uint64_t prevID =

2197 llvm::SmallVector<std::pair<unsigned, uint64_t>> currentOrder = {{0, prevID}};

2198 for (auto item : llvm::drop_begin(llvm::enumerate(value.getUses()))) {

2200 item.value(), operationIDs.at(item.value().getOwner()));

2201 alreadySorted &= prevID > currentID;

2202 currentOrder.push_back({item.index(), currentID});

2203 prevID = currentID;

2204 }

2205

2206

2207

2208 if (alreadySorted && !hasIncomingOrder)

2210

2211

2212

2213 if (!alreadySorted)

2214 std::sort(

2215 currentOrder.begin(), currentOrder.end(),

2216 [](auto elem1, auto elem2) { return elem1.second > elem2.second; });

2217

2218 if (!hasIncomingOrder) {

2219

2220

2221

2222 SmallVector shuffle(llvm::make_first_range(currentOrder));

2225 }

2226

2227

2228 UseListOrderStorage customOrder =

2230 SmallVector<unsigned, 4> shuffle = std::move(customOrder.indices);

2231 uint64_t numUses = value.getNumUses();

2232

2233

2234

2235

2236 if (customOrder.isIndexPairEncoding) {

2237

2238 if (shuffle.size() & 1)

2239 return failure();

2240

2241 SmallVector<unsigned, 4> newShuffle(numUses);

2242 size_t idx = 0;

2243 std::iota(newShuffle.begin(), newShuffle.end(), idx);

2244 for (idx = 0; idx < shuffle.size(); idx += 2)

2245 newShuffle[shuffle[idx]] = shuffle[idx + 1];

2246

2247 shuffle = std::move(newShuffle);

2248 }

2249

2250

2251

2252

2254 uint64_t accumulator = 0;

2255 for (const auto &elem : shuffle) {

2256 if (!set.insert(elem).second)

2257 return failure();

2258 accumulator += elem;

2259 }

2260 if (numUses != shuffle.size() ||

2261 accumulator != (((numUses - 1) * numUses) >> 1))

2262 return failure();

2263

2264

2265

2266 shuffle = SmallVector<unsigned, 4>(llvm::map_range(

2267 currentOrder, [&](auto item) { return shuffle[item.first]; }));

2270}

2271

2272LogicalResult BytecodeReader::Impl::processUseLists(Operation *topLevelOp) {

2273

2274

2275

2276 unsigned operationID = 0;

2278 [&](Operation *op) { operationIDs.try_emplace(op, operationID++); });

2279

2280 auto blockWalk = topLevelOp->walk([this](Block *block) {

2282 if (failed(sortUseListOrder(arg)))

2285 });

2286

2287 auto resultWalk = topLevelOp->walk([this](Operation *op) {

2292 });

2293

2294 return failure(blockWalk.wasInterrupted() || resultWalk.wasInterrupted());

2295}

2296

2297

2298

2299

2300

2301LogicalResult

2302BytecodeReader::Impl::parseIRSection(ArrayRef<uint8_t> sectionData,

2304 EncodingReader reader(sectionData, fileLoc);

2305

2306

2307 std::vector regionStack;

2308

2309

2310 OwningOpRef moduleOp = ModuleOp::create(fileLoc);

2311 regionStack.emplace_back(*moduleOp, &reader, true);

2312 regionStack.back().curBlocks.push_back(moduleOp->getBody());

2313 regionStack.back().curBlock = regionStack.back().curRegion->begin();

2314 if (failed(parseBlockHeader(reader, regionStack.back())))

2315 return failure();

2316 valueScopes.emplace_back();

2317 valueScopes.back().push(regionStack.back());

2318

2319

2320 while (!regionStack.empty())

2322 return failure();

2323 if (!forwardRefOps.empty()) {

2324 return reader.emitError(

2325 "not all forward unresolved forward operand references");

2326 }

2327

2328

2329 if (failed(processUseLists(*moduleOp)))

2330 return reader.emitError(

2331 "parsed use-list orders were invalid and could not be applied");

2332

2333

2334 for (const std::unique_ptr &byteCodeDialect : dialects) {

2335

2336

2337 if (!byteCodeDialect->loadedVersion)

2338 continue;

2339 if (byteCodeDialect->interface &&

2340 failed(byteCodeDialect->interface->upgradeFromVersion(

2341 *moduleOp, *byteCodeDialect->loadedVersion)))

2342 return failure();

2343 }

2344

2345

2347 return failure();

2348

2349

2350 auto &parsedOps = moduleOp->getBody()->getOperations();

2352 destOps.splice(destOps.end(), parsedOps, parsedOps.begin(), parsedOps.end());

2354}

2355

2356LogicalResult

2357BytecodeReader::Impl::parseRegions(std::vector &regionStack,

2358 RegionReadState &readState) {

2359 const auto checkSectionAlignment = [&](unsigned alignment) {

2360 return this->checkSectionAlignment(

2361 alignment, [&](const auto &msg) { return emitError(fileLoc, msg); });

2362 };

2363

2364

2365

2366

2367 for (; readState.curRegion != readState.endRegion; ++readState.curRegion) {

2368

2369

2370

2371

2373 if (failed(parseRegion(readState)))

2374 return failure();

2375

2376

2377 if (readState.curRegion->empty())

2378 continue;

2379 }

2380

2381

2382 EncodingReader &reader = *readState.reader;

2383 do {

2384 while (readState.numOpsRemaining--) {

2385

2386

2387 bool isIsolatedFromAbove = false;

2388 FailureOr<Operation *> op =

2389 parseOpWithoutRegions(reader, readState, isIsolatedFromAbove);

2391 return failure();

2392

2393

2394

2395

2396

2397 if ((*op)->getNumRegions()) {

2398 RegionReadState childState(*op, &reader, isIsolatedFromAbove);

2399

2400

2403 ArrayRef<uint8_t> sectionData;

2404 if (failed(reader.parseSection(sectionID, checkSectionAlignment,

2405 sectionData)))

2406 return failure();

2408 return emitError(fileLoc, "expected IR section for region");

2409 childState.owningReader =

2410 std::make_unique(sectionData, fileLoc);

2411 childState.reader = childState.owningReader.get();

2412

2413

2414

2415 if (lazyLoading && (!lazyOpsCallback || !lazyOpsCallback(*op))) {

2416 lazyLoadableOps.emplace_back(*op, std::move(childState));

2417 lazyLoadableOpsMap.try_emplace(*op,

2418 std::prev(lazyLoadableOps.end()));

2419 continue;

2420 }

2421 }

2422 regionStack.push_back(std::move(childState));

2423

2424

2425 if (isIsolatedFromAbove)

2426 valueScopes.emplace_back();

2428 }

2429 }

2430

2431

2432 if (++readState.curBlock == readState.curRegion->end())

2433 break;

2434 if (failed(parseBlockHeader(reader, readState)))

2435 return failure();

2436 } while (true);

2437

2438

2439 readState.curBlock = {};

2440 valueScopes.back().pop(readState);

2441 }

2442

2443

2444

2445 if (readState.isIsolatedFromAbove) {

2446 assert(!valueScopes.empty() && "Expect a valueScope after reading region");

2447 valueScopes.pop_back();

2448 }

2449 assert(!regionStack.empty() && "Expect a regionStack after reading region");

2450 regionStack.pop_back();

2452}

2453

2454FailureOr<Operation *>

2455BytecodeReader::Impl::parseOpWithoutRegions(EncodingReader &reader,

2456 RegionReadState &readState,

2457 bool &isIsolatedFromAbove) {

2458

2459 std::optional wasRegistered;

2460 FailureOr opName = parseOpName(reader, wasRegistered);

2462 return failure();

2463

2464

2465

2466 uint8_t opMask;

2467 if (failed(reader.parseByte(opMask)))

2468 return failure();

2469

2470

2471 LocationAttr opLoc;

2473 return failure();

2474

2475

2476

2477 OperationState opState(opLoc, *opName);

2478

2479

2481 DictionaryAttr dictAttr;

2483 return failure();

2485 }

2486

2488

2489

2490 if (!wasRegistered)

2492 "Unexpected missing `wasRegistered` opname flag at "

2493 "bytecode version ")

2494 << version << " with properties.";

2495

2496

2497

2498 if (wasRegistered) {

2499 DialectReader dialectReader(attrTypeReader, stringReader, resourceReader,

2500 dialectsMap, reader, version);

2502 propertiesReader.read(fileLoc, dialectReader, &*opName, opState)))

2503 return failure();

2504 } else {

2505

2506

2508 return failure();

2509 }

2510 }

2511

2512

2514 uint64_t numResults;

2515 if (failed(reader.parseVarInt(numResults)))

2516 return failure();

2517 opState.types.resize(numResults);

2518 for (int i = 0, e = numResults; i < e; ++i)

2520 return failure();

2521 }

2522

2523

2525 uint64_t numOperands;

2526 if (failed(reader.parseVarInt(numOperands)))

2527 return failure();

2528 opState.operands.resize(numOperands);

2529 for (int i = 0, e = numOperands; i < e; ++i)

2530 if (!(opState.operands[i] = parseOperand(reader)))

2531 return failure();

2532 }

2533

2534

2536 uint64_t numSuccs;

2537 if (failed(reader.parseVarInt(numSuccs)))

2538 return failure();

2539 opState.successors.resize(numSuccs);

2540 for (int i = 0, e = numSuccs; i < e; ++i) {

2542 "successor")))

2543 return failure();

2544 }

2545 }

2546

2547

2548

2549 std::optional resultIdxToUseListMap = std::nullopt;

2552 size_t numResults = opState.types.size();

2553 auto parseResult = parseUseListOrderForRange(reader, numResults);

2554 if (failed(parseResult))

2555 return failure();

2556 resultIdxToUseListMap = std::move(*parseResult);

2557 }

2558

2559

2561 uint64_t numRegions;

2562 if (failed(reader.parseVarIntWithFlag(numRegions, isIsolatedFromAbove)))

2563 return failure();

2564

2565 opState.regions.reserve(numRegions);

2566 for (int i = 0, e = numRegions; i < e; ++i)

2567 opState.regions.push_back(std::make_unique());

2568 }

2569

2570

2572 readState.curBlock->push_back(op);

2573

2574

2575

2576

2577 if (readState.numValues && op->getNumResults() &&

2579 return failure();

2580

2581

2582

2583 if (resultIdxToUseListMap.has_value()) {

2584 for (size_t idx = 0; idx < op->getNumResults(); idx++) {

2585 if (resultIdxToUseListMap->contains(idx)) {

2587 resultIdxToUseListMap->at(idx));

2588 }

2589 }

2590 }

2591 return op;

2592}

2593

2594LogicalResult BytecodeReader::Impl::parseRegion(RegionReadState &readState) {

2595 EncodingReader &reader = *readState.reader;

2596

2597

2598 uint64_t numBlocks;

2599 if (failed(reader.parseVarInt(numBlocks)))

2600 return failure();

2601

2602

2603 if (numBlocks == 0)

2605

2606

2607 uint64_t numValues;

2608 if (failed(reader.parseVarInt(numValues)))

2609 return failure();

2610 readState.numValues = numValues;

2611

2612

2613

2614 readState.curBlocks.clear();

2615 readState.curBlocks.reserve(numBlocks);

2616 for (uint64_t i = 0; i < numBlocks; ++i) {

2617 readState.curBlocks.push_back(new Block());

2618 readState.curRegion->push_back(readState.curBlocks.back());

2619 }

2620

2621

2622 valueScopes.back().push(readState);

2623

2624

2625 readState.curBlock = readState.curRegion->begin();

2626 return parseBlockHeader(reader, readState);

2627}

2628

2629LogicalResult

2630BytecodeReader::Impl::parseBlockHeader(EncodingReader &reader,

2631 RegionReadState &readState) {

2632 bool hasArgs;

2633 if (failed(reader.parseVarIntWithFlag(readState.numOpsRemaining, hasArgs)))

2634 return failure();

2635

2636

2637 if (hasArgs && failed(parseBlockArguments(reader, &*readState.curBlock)))

2638 return failure();

2639

2640

2643

2644 uint8_t hasUseListOrders = 0;

2645 if (hasArgs && failed(reader.parseByte(hasUseListOrders)))

2646 return failure();

2647

2648 if (!hasUseListOrders)

2650

2651 Block &blk = *readState.curBlock;

2652 auto argIdxToUseListMap =

2653 parseUseListOrderForRange(reader, blk.getNumArguments());

2654 if (failed(argIdxToUseListMap) || argIdxToUseListMap->empty())

2655 return failure();

2656

2657 for (size_t idx = 0; idx < blk.getNumArguments(); idx++)

2658 if (argIdxToUseListMap->contains(idx))

2660 argIdxToUseListMap->at(idx));

2661

2662

2664}

2665

2666LogicalResult BytecodeReader::Impl::parseBlockArguments(EncodingReader &reader,

2668

2669 uint64_t numArgs;

2670 if (failed(reader.parseVarInt(numArgs)))

2671 return failure();

2672

2673 SmallVector argTypes;

2674 SmallVector argLocs;

2675 argTypes.reserve(numArgs);

2676 argLocs.reserve(numArgs);

2677

2678 Location unknownLoc = UnknownLoc::get(config.getContext());

2679 while (numArgs--) {

2680 Type argType;

2681 LocationAttr argLoc = unknownLoc;

2683

2684 uint64_t typeIdx;

2685 bool hasLoc;

2686 if (failed(reader.parseVarIntWithFlag(typeIdx, hasLoc)) ||

2687 !(argType = attrTypeReader.resolveType(typeIdx)))

2688 return failure();

2690 return failure();

2691 } else {

2692

2695 return failure();

2696 }

2697 argTypes.push_back(argType);

2698 argLocs.push_back(argLoc);

2699 }

2701 return defineValues(reader, block->getArguments());

2702}

2703

2704

2705

2706

2707

2708Value BytecodeReader::Impl::parseOperand(EncodingReader &reader) {

2709 std::vector &values = valueScopes.back().values;

2710 Value *value = nullptr;

2712 return Value();

2713

2714

2715 if (!*value)

2716 *value = createForwardRef();

2717 return *value;

2718}

2719

2720LogicalResult BytecodeReader::Impl::defineValues(EncodingReader &reader,

2722 ValueScope &valueScope = valueScopes.back();

2723 std::vector &values = valueScope.values;

2724

2725 unsigned &valueID = valueScope.nextValueIDs.back();

2726 unsigned valueIDEnd = valueID + newValues.size();

2727 if (valueIDEnd > values.size()) {

2728 return reader.emitError(

2729 "value index range was outside of the expected range for "

2730 "the parent region, got [",

2731 valueID, ", ", valueIDEnd, "), but the maximum index was ",

2732 values.size() - 1);

2733 }

2734

2735

2736 for (unsigned i = 0, e = newValues.size(); i != e; ++i, ++valueID) {

2737 Value newValue = newValues[i];

2738

2739

2740 if (Value oldValue = std::exchange(values[valueID], newValue)) {

2741 Operation *forwardRefOp = oldValue.getDefiningOp();

2742

2743

2744

2745

2746 assert(forwardRefOp && forwardRefOp->getBlock() == &forwardRefOps &&

2747 "value index was already defined?");

2748

2749 oldValue.replaceAllUsesWith(newValue);

2750 forwardRefOp->moveBefore(&openForwardRefOps, openForwardRefOps.end());

2751 }

2752 }

2754}

2755

2756Value BytecodeReader::Impl::createForwardRef() {

2757

2758

2759 if (!openForwardRefOps.empty()) {

2760 Operation *op = &openForwardRefOps.back();

2761 op->moveBefore(&forwardRefOps, forwardRefOps.end());

2762 } else {

2764 }

2765 return forwardRefOps.back().getResult(0);

2766}

2767

2768

2769

2770

2771

2773

2775 llvm::MemoryBufferRef buffer, const ParserConfig &config, bool lazyLoading,

2776 const std::shared_ptrllvm::SourceMgr &bufferOwnerRef) {

2779 0, 0);

2780 impl = std::make_unique(sourceFileLoc, config, lazyLoading, buffer,

2781 bufferOwnerRef);

2782}

2783

2786 return impl->read(block, lazyOpsCallback);

2787}

2788

2790 return impl->getNumOpsToMaterialize();

2791}

2792

2794 return impl->isMaterializable(op);

2795}

2796

2799 return impl->materialize(op, lazyOpsCallback);

2800}

2801

2802LogicalResult

2804 return impl->finalize(shouldMaterialize);

2805}

2806

2808 return buffer.getBuffer().starts_with("ML\xefR");

2809}

2810

2811

2812

2813

2814static LogicalResult

2817 const std::shared_ptrllvm::SourceMgr &bufferOwnerRef) {

2820 0, 0);

2823 "input buffer is not an MLIR bytecode file");

2824 }

2825

2827 buffer, bufferOwnerRef);

2828 return reader.read(block, nullptr);

2829}

2830

2835LogicalResult

2839 *sourceMgr->getMemoryBuffer(sourceMgr->getMainFileID()), block, config,

2840 sourceMgr);

2841}

static LogicalResult parseDialectGrouping(EncodingReader &reader, MutableArrayRef< std::unique_ptr< BytecodeDialect > > dialects, function_ref< LogicalResult(BytecodeDialect *)> entryCallback)

Parse a single dialect group encoded in the byte stream.

Definition BytecodeReader.cpp:560

static LogicalResult readBytecodeFileImpl(llvm::MemoryBufferRef buffer, Block *block, const ParserConfig &config, const std::shared_ptr< llvm::SourceMgr > &bufferOwnerRef)

Read the bytecode from the provided memory buffer reference.

Definition BytecodeReader.cpp:2815

static bool isSectionOptional(bytecode::Section::ID sectionID, int version)

Returns true if the given top-level section ID is optional.

Definition BytecodeReader.cpp:67

static LogicalResult parseResourceGroup(Location fileLoc, bool allowEmpty, EncodingReader &offsetReader, EncodingReader &resourceReader, StringSectionReader &stringReader, T *handler, const std::shared_ptr< llvm::SourceMgr > &bufferOwnerRef, function_ref< StringRef(StringRef)> remapKey={}, function_ref< LogicalResult(StringRef)> processKeyFn={})

Definition BytecodeReader.cpp:688

static LogicalResult resolveEntry(EncodingReader &reader, RangeT &entries, uint64_t index, T &entry, StringRef entryStr)

Resolve an index into the given entry list.

Definition BytecodeReader.cpp:389

static LogicalResult parseEntry(EncodingReader &reader, RangeT &entries, T &entry, StringRef entryStr)

Parse and resolve an index into the given entry list.

Definition BytecodeReader.cpp:405

LogicalResult initialize(unsigned origNumLoops, ArrayRef< ReassociationIndices > foldedIterationDims)

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

static ParseResult parseRegions(OpAsmParser &parser, OperationState &state, unsigned nRegions=1)

MutableArrayRef< char > getMutableData()

Return a mutable reference to the raw underlying data of this blob.

ArrayRef< char > getData() const

Return the raw underlying data of this blob.

bool isMutable() const

Return if the data of this blob is mutable.

MLIRContext * getContext() const

Return the context this attribute belongs to.

Block represents an ordered list of Operations.

BlockArgument getArgument(unsigned i)

unsigned getNumArguments()

iterator_range< args_iterator > addArguments(TypeRange types, ArrayRef< Location > locs)

Add one argument to the argument list for each type specified in the list.

OpListType & getOperations()

BlockArgListType getArguments()

ArrayRef< std::unique_ptr< AttrTypeBytecodeReader< Type > > > getTypeCallbacks() const

ArrayRef< std::unique_ptr< AttrTypeBytecodeReader< Attribute > > > getAttributeCallbacks() const

Returns the callbacks available to the parser.

This class is used to read a bytecode buffer and translate it into MLIR.

Definition BytecodeReader.cpp:1510

LogicalResult materializeAll()

Materialize all operations.

Definition BytecodeReader.cpp:1555

LogicalResult read(Block *block, llvm::function_ref< bool(Operation *)> lazyOps)

Read the bytecode defined within buffer into the given block.

Definition BytecodeReader.cpp:1854

bool isMaterializable(Operation *op)

Definition BytecodeReader.cpp:1538

Impl(Location fileLoc, const ParserConfig &config, bool lazyLoading, llvm::MemoryBufferRef buffer, const std::shared_ptr< llvm::SourceMgr > &bufferOwnerRef)

Definition BytecodeReader.cpp:1518

LogicalResult finalize(function_ref< bool(Operation *)> shouldMaterialize)

Finalize the lazy-loading by calling back with every op that hasn't been materialized to let the clie...

Definition BytecodeReader.cpp:1567

LogicalResult materialize(Operation *op, llvm::function_ref< bool(Operation *)> lazyOpsCallback)

Materialize the provided operation, invoke the lazyOpsCallback on every newly found lazy operation.

Definition BytecodeReader.cpp:1543

int64_t getNumOpsToMaterialize() const

Return the number of ops that haven't been materialized yet.

Definition BytecodeReader.cpp:1536

LogicalResult materialize(Operation *op, llvm::function_ref< bool(Operation *)> lazyOpsCallback=[](Operation *) { return false;})

Materialize the provide operation.

Definition BytecodeReader.cpp:2797

LogicalResult finalize(function_ref< bool(Operation *)> shouldMaterialize=[](Operation *) { return true;})

Finalize the lazy-loading by calling back with every op that hasn't been materialized to let the clie...

Definition BytecodeReader.cpp:2803

~BytecodeReader()

Definition BytecodeReader.cpp:2772

BytecodeReader(llvm::MemoryBufferRef buffer, const ParserConfig &config, bool lazyLoad, const std::shared_ptr< llvm::SourceMgr > &bufferOwnerRef={})

Create a bytecode reader for the given buffer.

Definition BytecodeReader.cpp:2774

int64_t getNumOpsToMaterialize() const

Return the number of ops that haven't been materialized yet.

Definition BytecodeReader.cpp:2789

bool isMaterializable(Operation *op)

Return true if the provided op is materializable.

Definition BytecodeReader.cpp:2793

LogicalResult readTopLevel(Block *block, llvm::function_ref< bool(Operation *)> lazyOps=[](Operation *) { return false;})

Read the operations defined within the given memory buffer, containing MLIR bytecode,...

Definition BytecodeReader.cpp:2784

This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine.

static FileLineColLoc get(StringAttr filename, unsigned line, unsigned column)

This class represents a diagnostic that is inflight and set to be reported.

InFlightDiagnostic & append(Args &&...args) &

Append arguments to the diagnostic.

This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...

MLIRContext * getContext() const

Return the context this location is uniqued in.

MLIRContext is the top-level object for a collection of MLIR operations.

T * getOrLoadDialect()

Get (or create) a dialect for the given derived dialect type.

bool allowsUnregisteredDialects()

Return true if we allow to create operation for unregistered dialects.

StringRef getStringRef() const

Return the name of this operation. This always succeeds.

bool isRegistered() const

Return if this operation is registered.

T::Concept * getInterface() const

Returns an instance of the concept object for the given interface if it was registered to this operat...

Operation is the basic unit of execution within MLIR.

void dropAllReferences()

This drops all operand uses from this operation, which is an essential step in breaking cyclic depend...

Block * getBlock()

Returns the operation block that contains this operation.

OpResult getResult(unsigned idx)

Get the 'idx'th result of this operation.

static Operation * create(Location location, OperationName name, TypeRange resultTypes, ValueRange operands, NamedAttrList &&attributes, OpaqueProperties properties, BlockRange successors, unsigned numRegions)

Create a new Operation with the specific fields.

void moveBefore(Operation *existingOp)

Unlink this operation from its current block and insert it right before existingOp which may be in th...

std::enable_if_t< llvm::function_traits< std::decay_t< FnT > >::num_args==1, RetT > walk(FnT &&callback)

Walk the operation by calling the callback for each nested operation (including this one),...

result_range getResults()

void erase()

Remove this operation from its parent block and delete it.

unsigned getNumResults()

Return the number of results held by this operation.

This class represents a configuration for the MLIR assembly parser.

BytecodeReaderConfig & getBytecodeReaderConfig() const

Returns the parsing configurations associated to the bytecode read.

BlockListType::iterator iterator

This diagnostic handler is a simple RAII class that registers and erases a diagnostic handler on a gi...

static AsmResourceBlob allocateWithAlign(ArrayRef< char > data, size_t align, AsmResourceBlob::DeleterFn deleter={}, bool dataIsMutable=false)

Create a new unmanaged resource directly referencing the provided data.

This class provides an abstraction over the different types of ranges over Values.

bool use_empty() const

Returns true if this value has no uses.

void shuffleUseList(ArrayRef< unsigned > indices)

Shuffle the use list order according to the provided indices.

use_range getUses() const

Returns a range of all uses, which is useful for iterating over all uses.

void * getAsOpaquePointer() const

Methods for supporting PointerLikeTypeTraits.

unsigned getNumUses() const

This method computes the number of uses of this Value.

bool hasOneUse() const

Returns true if this value has exactly one use.

use_iterator use_begin() const

static WalkResult advance()

static WalkResult interrupt()

@ kAttrType

This section contains the attributes and types referenced within an IR module.

@ kAttrTypeOffset

This section contains the offsets for the attribute and types within the AttrType section.

@ kIR

This section contains the list of operations serialized into the bytecode, and their nested regions/o...

@ kResource

This section contains the resources of the bytecode.

@ kResourceOffset

This section contains the offsets of resources within the Resource section.

@ kDialect

This section contains the dialects referenced within an IR module.

@ kString

This section contains strings referenced within the bytecode.

@ kDialectVersions

This section contains the versions of each dialect.

@ kProperties

This section contains the properties for the operations.

@ kNumSections

The total number of section types.

static uint64_t getUseID(OperandT &val, unsigned ownerID)

Get the unique ID of a value use.

@ kUseListOrdering

Use-list ordering started to be encoded in version 3.

@ kAlignmentByte

An arbitrary value used to fill alignment padding.

@ kVersion

The current bytecode version.

@ kLazyLoading

Support for lazy-loading of isolated region was added in version 2.

@ kDialectVersioning

Dialects versioning was added in version 1.

@ kElideUnknownBlockArgLocation

Avoid recording unknown locations on block arguments (compression) started in version 4.

@ kNativePropertiesEncoding

Support for encoding properties natively in bytecode instead of merged with the discardable attribute...

@ kMinSupportedVersion

The minimum supported version of the bytecode.

Include the generated interface declarations.

InFlightDiagnostic emitWarning(Location loc)

Utility method to emit a warning message using this location.

StringRef toString(AsmResourceEntryKind kind)

static LogicalResult readResourceHandle(DialectBytecodeReader &reader, FailureOr< T > &value, Ts &&...params)

Helper for resource handle reading that returns LogicalResult.

bool isBytecode(llvm::MemoryBufferRef buffer)

Returns true if the given buffer starts with the magic bytes that signal MLIR bytecode.

Definition BytecodeReader.cpp:2807

const FrozenRewritePatternSet GreedyRewriteConfig config

llvm::DenseSet< ValueT, ValueInfoT > DenseSet

InFlightDiagnostic emitError(Location loc)

Utility method to emit an error message using this location.

Attribute parseAttribute(llvm::StringRef attrStr, MLIRContext *context, Type type={}, size_t *numRead=nullptr, bool isKnownNullTerminated=false)

This parses a single MLIR attribute to an MLIR context if it was valid.

auto get(MLIRContext *context, Ts &&...params)

Helper method that injects context only if needed, this helps unify some of the attribute constructio...

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.

llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap

AsmResourceEntryKind

This enum represents the different kinds of resource values.

LogicalResult readBytecodeFile(llvm::MemoryBufferRef buffer, Block *block, const ParserConfig &config)

Read the operations defined within the given memory buffer, containing MLIR bytecode,...

Definition BytecodeReader.cpp:2831

LogicalResult verify(Operation *op, bool verifyRecursively=true)

Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...

llvm::function_ref< Fn > function_ref

SmallVector< Block *, 1 > successors

Successors of this operation and their respective operands.

SmallVector< Value, 4 > operands

SmallVector< std::unique_ptr< Region >, 1 > regions

Regions that the op will hold.

Attribute propertiesAttr

This Attribute is used to opaquely construct the properties of the operation.

SmallVector< Type, 4 > types

Types of the results of this operation.