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> §ionData) {
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 ®ionStack,
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] && (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 ®ionStack,
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.