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"
34 #define DEBUG_TYPE "mlir-bytecode-reader"
46 return "AttrType (2)";
48 return "AttrTypeOffset (3)";
52 return "Resource (5)";
54 return "ResourceOffset (6)";
56 return "DialectVersions (7)";
58 return "Properties (8)";
60 return (
"Unknown (" + Twine(
static_cast<unsigned>(sectionID)) +
")").str();
80 llvm_unreachable(
"unknown section ID");
89 class EncodingReader {
92 : buffer(contents), dataIt(buffer.begin()), fileLoc(fileLoc) {}
93 explicit EncodingReader(StringRef contents,
Location fileLoc)
94 : EncodingReader({
reinterpret_cast<const uint8_t *
>(contents.data()),
99 bool empty()
const {
return dataIt == buffer.end(); }
102 size_t size()
const {
return buffer.end() - dataIt; }
105 LogicalResult alignTo(
unsigned alignment) {
106 if (!llvm::isPowerOf2_32(alignment))
107 return emitError(
"expected alignment to be a power-of-two");
109 auto isUnaligned = [&](
const uint8_t *ptr) {
110 return ((uintptr_t)ptr & (alignment - 1)) != 0;
114 while (isUnaligned(dataIt)) {
116 if (failed(parseByte(padding)))
119 return emitError(
"expected alignment byte (0xCB), but got: '0x" +
120 llvm::utohexstr(padding) +
"'");
126 if (LLVM_UNLIKELY(isUnaligned(dataIt))) {
127 return emitError(
"expected data iterator aligned to ", alignment,
128 ", but got pointer: '0x" +
129 llvm::utohexstr((uintptr_t)dataIt) +
"'");
136 template <
typename... Args>
143 template <
typename T>
144 LogicalResult parseByte(T &value) {
146 return emitError(
"attempting to parse a byte at the end of the bytecode");
147 value =
static_cast<T
>(*dataIt++);
152 if (length > size()) {
153 return emitError(
"attempting to parse ", length,
" bytes when only ",
156 result = {dataIt, length};
162 LogicalResult parseBytes(
size_t length, uint8_t *result) {
163 if (length > size()) {
164 return emitError(
"attempting to parse ", length,
" bytes when only ",
167 memcpy(result, dataIt, length);
175 uint64_t &alignment) {
177 if (failed(parseVarInt(alignment)) || failed(parseVarInt(dataSize)) ||
178 failed(alignTo(alignment)))
180 return parseBytes(dataSize, data);
190 LogicalResult parseVarInt(uint64_t &result) {
192 if (failed(parseByte(result)))
197 if (LLVM_LIKELY(result & 1)) {
205 if (LLVM_UNLIKELY(result == 0)) {
206 llvm::support::ulittle64_t resultLE;
207 if (failed(parseBytes(
sizeof(resultLE),
208 reinterpret_cast<uint8_t *
>(&resultLE))))
213 return parseMultiByteVarInt(result);
219 LogicalResult parseSignedVarInt(uint64_t &result) {
220 if (failed(parseVarInt(result)))
223 result = (result >> 1) ^ (~(result & 1) + 1);
229 LogicalResult parseVarIntWithFlag(uint64_t &result,
bool &flag) {
230 if (failed(parseVarInt(result)))
238 LogicalResult skipBytes(
size_t length) {
239 if (length > size()) {
240 return emitError(
"attempting to skip ", length,
" bytes when only ",
249 LogicalResult parseNullTerminatedString(StringRef &result) {
250 const char *startIt = (
const char *)dataIt;
251 const char *nulIt = (
const char *)memchr(startIt, 0, size());
254 "malformed null-terminated string, no null character found");
256 result = StringRef(startIt, nulIt - startIt);
257 dataIt = (
const uint8_t *)nulIt + 1;
265 uint8_t sectionIDAndHasAlignment;
267 if (failed(parseByte(sectionIDAndHasAlignment)) ||
268 failed(parseVarInt(length)))
275 bool hasAlignment = sectionIDAndHasAlignment & 0b10000000;
280 return emitError(
"invalid section ID: ",
unsigned(sectionID));
285 if (failed(parseVarInt(alignment)) || failed(alignTo(alignment)))
290 return parseBytes(
static_cast<size_t>(length), sectionData);
293 Location getLoc()
const {
return fileLoc; }
302 LLVM_ATTRIBUTE_NOINLINE LogicalResult parseMultiByteVarInt(uint64_t &result) {
308 uint32_t numBytes = llvm::countr_zero<uint32_t>(result);
309 assert(numBytes > 0 && numBytes <= 7 &&
310 "unexpected number of trailing zeros in varint encoding");
313 llvm::support::ulittle64_t resultLE(result);
315 parseBytes(numBytes,
reinterpret_cast<uint8_t *
>(&resultLE) + 1)))
320 result = resultLE >> (numBytes + 1);
328 const uint8_t *dataIt;
339 template <
typename RangeT,
typename T>
340 static LogicalResult
resolveEntry(EncodingReader &reader, RangeT &entries,
341 uint64_t index, T &entry,
342 StringRef entryStr) {
343 if (index >= entries.size())
344 return reader.emitError(
"invalid ", entryStr,
" index: ", index);
347 if constexpr (std::is_convertible_v<llvm::detail::ValueOfRange<RangeT>, T>)
348 entry = entries[index];
350 entry = &entries[index];
355 template <
typename RangeT,
typename T>
356 static LogicalResult
parseEntry(EncodingReader &reader, RangeT &entries,
357 T &entry, StringRef entryStr) {
359 if (failed(reader.parseVarInt(entryIdx)))
361 return resolveEntry(reader, entries, entryIdx, entry, entryStr);
371 class StringSectionReader {
378 LogicalResult parseString(EncodingReader &reader, StringRef &result)
const {
379 return parseEntry(reader, strings, result,
"string");
385 LogicalResult parseStringWithFlag(EncodingReader &reader, StringRef &result,
388 if (failed(reader.parseVarIntWithFlag(entryIdx, flag)))
390 return parseStringAtIndex(reader, entryIdx, result);
395 LogicalResult parseStringAtIndex(EncodingReader &reader, uint64_t index,
396 StringRef &result)
const {
397 return resolveEntry(reader, strings, index, result,
"string");
406 LogicalResult StringSectionReader::initialize(
Location fileLoc,
408 EncodingReader stringReader(sectionData, fileLoc);
412 if (failed(stringReader.parseVarInt(numStrings)))
414 strings.resize(numStrings);
418 size_t stringDataEndOffset = sectionData.size();
419 for (StringRef &
string : llvm::reverse(strings)) {
421 if (failed(stringReader.parseVarInt(stringSize)))
423 if (stringDataEndOffset < stringSize) {
424 return stringReader.emitError(
425 "string size exceeds the available data size");
429 size_t stringOffset = stringDataEndOffset - stringSize;
431 reinterpret_cast<const char *
>(sectionData.data() + stringOffset),
433 stringDataEndOffset = stringOffset;
438 if ((sectionData.size() - stringReader.size()) != stringDataEndOffset) {
439 return stringReader.emitError(
"unexpected trailing data between the "
440 "offsets for strings and their data");
453 struct BytecodeDialect {
458 LogicalResult load(
const DialectReader &reader,
MLIRContext *ctx);
462 Dialect *getLoadedDialect()
const {
464 "expected `load` to be invoked before `getLoadedDialect`");
471 std::optional<Dialect *> dialect;
485 std::unique_ptr<DialectVersion> loadedVersion;
489 struct BytecodeOperationName {
490 BytecodeOperationName(BytecodeDialect *dialect, StringRef name,
491 std::optional<bool> wasRegistered)
492 : dialect(dialect), name(name), wasRegistered(wasRegistered) {}
496 std::optional<OperationName> opName;
499 BytecodeDialect *dialect;
506 std::optional<bool> wasRegistered;
512 EncodingReader &reader,
514 function_ref<LogicalResult(BytecodeDialect *)> entryCallback) {
516 std::unique_ptr<BytecodeDialect> *dialect;
517 if (failed(
parseEntry(reader, dialects, dialect,
"dialect")))
520 if (failed(reader.parseVarInt(numEntries)))
523 for (uint64_t i = 0; i < numEntries; ++i)
524 if (failed(entryCallback(dialect->get())))
535 class ResourceSectionReader {
543 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef);
546 LogicalResult parseResourceHandle(EncodingReader &reader,
548 return parseEntry(reader, dialectResources, result,
"resource handle");
554 llvm::StringMap<std::string> dialectResourceHandleRenamingMap;
560 EncodingReader &reader, StringSectionReader &stringReader,
561 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef)
562 : key(key),
kind(
kind), reader(reader), stringReader(stringReader),
563 bufferOwnerRef(bufferOwnerRef) {}
564 ~ParsedResourceEntry()
override =
default;
566 StringRef getKey() const final {
return key; }
572 FailureOr<bool> parseAsBool() const final {
574 return emitError() <<
"expected a bool resource entry, but found a "
578 if (failed(reader.parseByte(value)))
582 FailureOr<std::string> parseAsString() const final {
584 return emitError() <<
"expected a string resource entry, but found a "
588 if (failed(stringReader.parseString(reader,
string)))
593 FailureOr<AsmResourceBlob>
594 parseAsBlob(BlobAllocatorFn allocator)
const final {
596 return emitError() <<
"expected a blob resource entry, but found a "
601 if (failed(reader.parseBlobAndAlignment(data, alignment)))
606 if (bufferOwnerRef) {
607 ArrayRef<char> charData(
reinterpret_cast<const char *
>(data.data()),
615 [bufferOwnerRef = bufferOwnerRef](
void *,
size_t,
size_t) {});
621 assert(llvm::isAddrAligned(llvm::Align(alignment), blob.
getData().data()) &&
623 "blob allocator did not return a properly aligned address");
631 EncodingReader &reader;
632 StringSectionReader &stringReader;
633 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef;
637 template <
typename T>
640 EncodingReader &offsetReader, EncodingReader &resourceReader,
641 StringSectionReader &stringReader, T *handler,
642 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef,
644 function_ref<LogicalResult(StringRef)> processKeyFn = {}) {
645 uint64_t numResources;
646 if (failed(offsetReader.parseVarInt(numResources)))
649 for (uint64_t i = 0; i < numResources; ++i) {
652 uint64_t resourceOffset;
654 if (failed(stringReader.parseString(offsetReader, key)) ||
655 failed(offsetReader.parseVarInt(resourceOffset)) ||
656 failed(offsetReader.parseByte(
kind)) ||
657 failed(resourceReader.parseBytes(resourceOffset, data)))
661 if ((processKeyFn && failed(processKeyFn(key))))
666 if (allowEmpty && data.empty())
674 EncodingReader entryReader(data, fileLoc);
676 ParsedResourceEntry entry(key,
kind, entryReader, stringReader,
678 if (failed(handler->parseResource(entry)))
680 if (!entryReader.empty()) {
681 return entryReader.emitError(
682 "unexpected trailing bytes in resource entry '", key,
"'");
688 LogicalResult ResourceSectionReader::initialize(
693 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef) {
694 EncodingReader resourceReader(sectionData, fileLoc);
695 EncodingReader offsetReader(offsetSectionData, fileLoc);
698 uint64_t numExternalResourceGroups;
699 if (failed(offsetReader.parseVarInt(numExternalResourceGroups)))
704 auto parseGroup = [&](
auto *handler,
bool allowEmpty =
false,
706 auto resolveKey = [&](StringRef key) -> StringRef {
707 auto it = dialectResourceHandleRenamingMap.find(key);
708 if (it == dialectResourceHandleRenamingMap.end())
714 stringReader, handler, bufferOwnerRef, resolveKey,
719 for (uint64_t i = 0; i < numExternalResourceGroups; ++i) {
721 if (failed(stringReader.parseString(offsetReader, key)))
728 emitWarning(fileLoc) <<
"ignoring unknown external resources for '" << key
732 if (failed(parseGroup(handler)))
738 while (!offsetReader.empty()) {
739 std::unique_ptr<BytecodeDialect> *dialect;
740 if (failed(
parseEntry(offsetReader, dialects, dialect,
"dialect")) ||
741 failed((*dialect)->load(dialectReader, ctx)))
743 Dialect *loadedDialect = (*dialect)->getLoadedDialect();
744 if (!loadedDialect) {
745 return resourceReader.emitError()
746 <<
"dialect '" << (*dialect)->name <<
"' is unknown";
748 const auto *handler = dyn_cast<OpAsmDialectInterface>(loadedDialect);
750 return resourceReader.emitError()
751 <<
"unexpected resources for dialect '" << (*dialect)->name <<
"'";
755 auto processResourceKeyFn = [&](StringRef key) -> LogicalResult {
756 FailureOr<AsmDialectResourceHandle> handle =
757 handler->declareResource(key);
758 if (failed(handle)) {
759 return resourceReader.emitError()
760 <<
"unknown 'resource' key '" << key <<
"' for dialect '"
761 << (*dialect)->name <<
"'";
763 dialectResourceHandleRenamingMap[key] = handler->getResourceKey(*handle);
764 dialectResources.push_back(*handle);
770 if (failed(parseGroup(handler,
true, processResourceKeyFn)))
785 class AttrTypeReader {
787 template <
typename T>
792 BytecodeDialect *dialect =
nullptr;
795 bool hasCustomEncoding =
false;
799 using AttrEntry = Entry<Attribute>;
800 using TypeEntry = Entry<Type>;
803 AttrTypeReader(
const StringSectionReader &stringReader,
804 const ResourceSectionReader &resourceReader,
805 const llvm::StringMap<BytecodeDialect *> &dialectsMap,
806 uint64_t &bytecodeVersion,
Location fileLoc,
808 : stringReader(stringReader), resourceReader(resourceReader),
809 dialectsMap(dialectsMap), fileLoc(fileLoc),
810 bytecodeVersion(bytecodeVersion), parserConfig(
config) {}
820 Attribute resolveAttribute(
size_t index) {
823 Type resolveType(
size_t index) {
return resolveEntry(types, index,
"Type"); }
828 if (failed(reader.parseVarInt(attrIdx)))
830 result = resolveAttribute(attrIdx);
831 return success(!!result);
833 LogicalResult parseOptionalAttribute(EncodingReader &reader,
837 if (failed(reader.parseVarIntWithFlag(attrIdx, flag)))
841 result = resolveAttribute(attrIdx);
842 return success(!!result);
845 LogicalResult
parseType(EncodingReader &reader,
Type &result) {
847 if (failed(reader.parseVarInt(typeIdx)))
849 result = resolveType(typeIdx);
850 return success(!!result);
853 template <
typename T>
858 if ((result = dyn_cast<T>(baseResult)))
860 return reader.emitError(
"expected attribute of type: ",
861 llvm::getTypeName<T>(),
", but got: ", baseResult);
866 template <
typename T>
868 StringRef entryType);
872 template <
typename T>
873 LogicalResult parseAsmEntry(T &result, EncodingReader &reader,
874 StringRef entryType);
878 template <
typename T>
879 LogicalResult parseCustomEntry(Entry<T> &entry, EncodingReader &reader,
880 StringRef entryType);
884 const StringSectionReader &stringReader;
888 const ResourceSectionReader &resourceReader;
892 const llvm::StringMap<BytecodeDialect *> &dialectsMap;
902 uint64_t &bytecodeVersion;
910 DialectReader(AttrTypeReader &attrTypeReader,
911 const StringSectionReader &stringReader,
912 const ResourceSectionReader &resourceReader,
913 const llvm::StringMap<BytecodeDialect *> &dialectsMap,
914 EncodingReader &reader, uint64_t &bytecodeVersion)
915 : attrTypeReader(attrTypeReader), stringReader(stringReader),
916 resourceReader(resourceReader), dialectsMap(dialectsMap),
917 reader(reader), bytecodeVersion(bytecodeVersion) {}
920 return reader.emitError(msg);
923 FailureOr<const DialectVersion *>
924 getDialectVersion(StringRef dialectName)
const override {
926 auto dialectEntry = dialectsMap.find(dialectName);
927 if (dialectEntry == dialectsMap.end())
932 if (failed(dialectEntry->getValue()->load(*
this, getLoc().
getContext())) ||
933 dialectEntry->getValue()->loadedVersion ==
nullptr)
935 return dialectEntry->getValue()->loadedVersion.get();
940 uint64_t getBytecodeVersion()
const override {
return bytecodeVersion; }
942 DialectReader withEncodingReader(EncodingReader &encReader)
const {
943 return DialectReader(attrTypeReader, stringReader, resourceReader,
944 dialectsMap, encReader, bytecodeVersion);
947 Location getLoc()
const {
return reader.getLoc(); }
953 LogicalResult readAttribute(
Attribute &result)
override {
954 return attrTypeReader.parseAttribute(reader, result);
956 LogicalResult readOptionalAttribute(
Attribute &result)
override {
957 return attrTypeReader.parseOptionalAttribute(reader, result);
959 LogicalResult readType(
Type &result)
override {
960 return attrTypeReader.parseType(reader, result);
965 if (failed(resourceReader.parseResourceHandle(reader, handle)))
974 LogicalResult readVarInt(uint64_t &result)
override {
975 return reader.parseVarInt(result);
978 LogicalResult readSignedVarInt(int64_t &result)
override {
979 uint64_t unsignedResult;
980 if (failed(reader.parseSignedVarInt(unsignedResult)))
982 result =
static_cast<int64_t
>(unsignedResult);
986 FailureOr<APInt> readAPIntWithKnownWidth(
unsigned bitWidth)
override {
990 if (failed(reader.parseByte(value)))
992 return APInt(bitWidth, value);
996 if (bitWidth <= 64) {
998 if (failed(reader.parseSignedVarInt(value)))
1000 return APInt(bitWidth, value);
1005 uint64_t numActiveWords;
1006 if (failed(reader.parseVarInt(numActiveWords)))
1009 for (uint64_t i = 0; i < numActiveWords; ++i)
1010 if (failed(reader.parseSignedVarInt(words[i])))
1012 return APInt(bitWidth, words);
1016 readAPFloatWithKnownSemantics(
const llvm::fltSemantics &semantics)
override {
1017 FailureOr<APInt> intVal =
1018 readAPIntWithKnownWidth(APFloat::getSizeInBits(semantics));
1021 return APFloat(semantics, *intVal);
1024 LogicalResult readString(StringRef &result)
override {
1025 return stringReader.parseString(reader, result);
1031 if (failed(reader.parseVarInt(dataSize)) ||
1032 failed(reader.parseBytes(dataSize, data)))
1034 result =
llvm::ArrayRef(
reinterpret_cast<const char *
>(data.data()),
1039 LogicalResult readBool(
bool &result)
override {
1040 return reader.parseByte(result);
1044 AttrTypeReader &attrTypeReader;
1045 const StringSectionReader &stringReader;
1046 const ResourceSectionReader &resourceReader;
1047 const llvm::StringMap<BytecodeDialect *> &dialectsMap;
1048 EncodingReader &reader;
1049 uint64_t &bytecodeVersion;
1053 class PropertiesSectionReader {
1057 if (sectionData.empty())
1059 EncodingReader propReader(sectionData, fileLoc);
1061 if (failed(propReader.parseVarInt(count)))
1064 if (failed(propReader.parseBytes(propReader.size(), propertiesBuffers)))
1067 EncodingReader offsetsReader(propertiesBuffers, fileLoc);
1068 offsetTable.reserve(count);
1069 for (
auto idx : llvm::seq<int64_t>(0, count)) {
1071 offsetTable.push_back(propertiesBuffers.size() - offsetsReader.size());
1074 if (failed(offsetsReader.parseVarInt(dataSize)) ||
1075 failed(offsetsReader.parseBytes(dataSize, rawProperties)))
1078 if (!offsetsReader.empty())
1079 return offsetsReader.emitError()
1080 <<
"Broken properties section: didn't exhaust the offsets table";
1084 LogicalResult read(
Location fileLoc, DialectReader &dialectReader,
1086 uint64_t propertiesIdx;
1087 if (failed(dialectReader.readVarInt(propertiesIdx)))
1089 if (propertiesIdx >= offsetTable.size())
1090 return dialectReader.emitError(
"Properties idx out-of-bound for ")
1092 size_t propertiesOffset = offsetTable[propertiesIdx];
1093 if (propertiesIdx >= propertiesBuffers.size())
1094 return dialectReader.emitError(
"Properties offset out-of-bound for ")
1102 EncodingReader reader(propertiesBuffers.drop_front(propertiesOffset),
1106 dialectReader.withEncodingReader(reader).readBlob(rawProperties)))
1110 EncodingReader reader(
1111 StringRef(rawProperties.begin(), rawProperties.size()), fileLoc);
1112 DialectReader propReader = dialectReader.withEncodingReader(reader);
1114 auto *iface = opName->
getInterface<BytecodeOpInterface>();
1116 return iface->readProperties(propReader, opState);
1118 return propReader.emitError(
1119 "has properties but missing BytecodeOpInterface for ")
1134 LogicalResult AttrTypeReader::initialize(
1137 EncodingReader offsetReader(offsetSectionData, fileLoc);
1140 uint64_t numAttributes, numTypes;
1141 if (failed(offsetReader.parseVarInt(numAttributes)) ||
1142 failed(offsetReader.parseVarInt(numTypes)))
1144 attributes.resize(numAttributes);
1145 types.resize(numTypes);
1149 uint64_t currentOffset = 0;
1150 auto parseEntries = [&](
auto &&range) {
1151 size_t currentIndex = 0, endIndex = range.size();
1154 auto parseEntryFn = [&](BytecodeDialect *dialect) -> LogicalResult {
1155 auto &entry = range[currentIndex++];
1158 if (failed(offsetReader.parseVarIntWithFlag(entrySize,
1159 entry.hasCustomEncoding)))
1163 if (currentOffset + entrySize > sectionData.size()) {
1164 return offsetReader.emitError(
1165 "Attribute or Type entry offset points past the end of section");
1168 entry.data = sectionData.slice(currentOffset, entrySize);
1169 entry.dialect = dialect;
1170 currentOffset += entrySize;
1173 while (currentIndex != endIndex)
1180 if (failed(parseEntries(attributes)) || failed(parseEntries(types)))
1184 if (!offsetReader.empty()) {
1185 return offsetReader.emitError(
1186 "unexpected trailing data in the Attribute/Type offset section");
1192 template <
typename T>
1194 StringRef entryType) {
1195 if (index >= entries.size()) {
1196 emitError(fileLoc) <<
"invalid " << entryType <<
" index: " << index;
1201 Entry<T> &entry = entries[index];
1206 EncodingReader reader(entry.data, fileLoc);
1209 if (entry.hasCustomEncoding) {
1210 if (failed(parseCustomEntry(entry, reader, entryType)))
1212 }
else if (failed(parseAsmEntry(entry.entry, reader, entryType))) {
1216 if (!reader.empty()) {
1217 reader.emitError(
"unexpected trailing bytes after " + entryType +
" entry");
1223 template <
typename T>
1224 LogicalResult AttrTypeReader::parseAsmEntry(T &result, EncodingReader &reader,
1225 StringRef entryType) {
1227 if (failed(reader.parseNullTerminatedString(asmStr)))
1233 if constexpr (std::is_same_v<T, Type>)
1243 if (numRead != asmStr.size()) {
1244 return reader.emitError(
"trailing characters found after ", entryType,
1245 " assembly format: ", asmStr.drop_front(numRead));
1250 template <
typename T>
1251 LogicalResult AttrTypeReader::parseCustomEntry(Entry<T> &entry,
1252 EncodingReader &reader,
1253 StringRef entryType) {
1254 DialectReader dialectReader(*
this, stringReader, resourceReader, dialectsMap,
1255 reader, bytecodeVersion);
1256 if (failed(entry.dialect->load(dialectReader, fileLoc.
getContext())))
1259 if constexpr (std::is_same_v<T, Type>) {
1261 for (
const auto &callback :
1262 parserConfig.getBytecodeReaderConfig().getTypeCallbacks()) {
1264 callback->read(dialectReader, entry.dialect->name, entry.entry)))
1272 reader = EncodingReader(entry.data, reader.getLoc());
1276 for (
const auto &callback :
1277 parserConfig.getBytecodeReaderConfig().getAttributeCallbacks()) {
1279 callback->read(dialectReader, entry.dialect->name, entry.entry)))
1287 reader = EncodingReader(entry.data, reader.getLoc());
1292 if (!entry.dialect->interface) {
1293 return reader.emitError(
"dialect '", entry.dialect->name,
1294 "' does not implement the bytecode interface");
1297 if constexpr (std::is_same_v<T, Type>)
1298 entry.entry = entry.dialect->interface->readType(dialectReader);
1300 entry.entry = entry.dialect->interface->readAttribute(dialectReader);
1302 return success(!!entry.entry);
1311 struct RegionReadState;
1312 using LazyLoadableOpsInfo =
1313 std::list<std::pair<Operation *, RegionReadState>>;
1314 using LazyLoadableOpsMap =
1319 llvm::MemoryBufferRef buffer,
1320 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef)
1321 :
config(
config), fileLoc(fileLoc), lazyLoading(lazyLoading),
1322 attrTypeReader(stringReader, resourceReader, dialectsMap, version,
1327 "builtin.unrealized_conversion_cast",
ValueRange(),
1329 buffer(buffer), bufferOwnerRef(bufferOwnerRef) {}
1345 this->lazyOpsCallback = lazyOpsCallback;
1346 auto resetlazyOpsCallback =
1347 llvm::make_scope_exit([&] { this->lazyOpsCallback =
nullptr; });
1348 auto it = lazyLoadableOpsMap.find(op);
1349 assert(it != lazyLoadableOpsMap.end() &&
1350 "materialize called on non-materializable op");
1356 while (!lazyLoadableOpsMap.empty()) {
1357 if (failed(
materialize(lazyLoadableOpsMap.begin())))
1368 while (!lazyLoadableOps.empty()) {
1369 Operation *op = lazyLoadableOps.begin()->first;
1370 if (shouldMaterialize(op)) {
1371 if (failed(
materialize(lazyLoadableOpsMap.find(op))))
1377 lazyLoadableOps.pop_front();
1378 lazyLoadableOpsMap.erase(op);
1384 LogicalResult
materialize(LazyLoadableOpsMap::iterator it) {
1385 assert(it != lazyLoadableOpsMap.end() &&
1386 "materialize called on non-materializable op");
1387 valueScopes.emplace_back();
1388 std::vector<RegionReadState> regionStack;
1389 regionStack.push_back(std::move(it->getSecond()->second));
1390 lazyLoadableOps.erase(it->getSecond());
1391 lazyLoadableOpsMap.erase(it);
1393 while (!regionStack.empty())
1394 if (failed(
parseRegions(regionStack, regionStack.back())))
1403 LogicalResult parseVersion(EncodingReader &reader);
1413 FailureOr<OperationName> parseOpName(EncodingReader &reader,
1414 std::optional<bool> &wasRegistered);
1420 template <
typename T>
1421 LogicalResult
parseAttribute(EncodingReader &reader, T &result) {
1422 return attrTypeReader.parseAttribute(reader, result);
1424 LogicalResult
parseType(EncodingReader &reader,
Type &result) {
1425 return attrTypeReader.parseType(reader, result);
1432 parseResourceSection(EncodingReader &reader,
1441 struct RegionReadState {
1442 RegionReadState(
Operation *op, EncodingReader *reader,
1443 bool isIsolatedFromAbove)
1444 : RegionReadState(op->getRegions(), reader, isIsolatedFromAbove) {}
1446 bool isIsolatedFromAbove)
1447 : curRegion(regions.begin()), endRegion(regions.end()), reader(reader),
1448 isIsolatedFromAbove(isIsolatedFromAbove) {}
1456 EncodingReader *reader;
1457 std::unique_ptr<EncodingReader> owningReader;
1460 unsigned numValues = 0;
1468 uint64_t numOpsRemaining = 0;
1471 bool isIsolatedFromAbove =
false;
1475 LogicalResult parseRegions(std::vector<RegionReadState> ®ionStack,
1476 RegionReadState &readState);
1477 FailureOr<Operation *> parseOpWithoutRegions(EncodingReader &reader,
1478 RegionReadState &readState,
1479 bool &isIsolatedFromAbove);
1481 LogicalResult parseRegion(RegionReadState &readState);
1482 LogicalResult parseBlockHeader(EncodingReader &reader,
1483 RegionReadState &readState);
1484 LogicalResult parseBlockArguments(EncodingReader &reader,
Block *block);
1491 Value parseOperand(EncodingReader &reader);
1494 LogicalResult defineValues(EncodingReader &reader,
ValueRange values);
1497 Value createForwardRef();
1505 struct UseListOrderStorage {
1506 UseListOrderStorage(
bool isIndexPairEncoding,
1508 : indices(std::move(indices)),
1509 isIndexPairEncoding(isIndexPairEncoding){};
1516 bool isIndexPairEncoding;
1525 FailureOr<UseListMapT> parseUseListOrderForRange(EncodingReader &reader,
1526 uint64_t rangeSize);
1529 LogicalResult sortUseListOrder(
Value value);
1533 LogicalResult processUseLists(
Operation *topLevelOp);
1543 void push(RegionReadState &readState) {
1544 nextValueIDs.push_back(values.size());
1545 values.resize(values.size() + readState.numValues);
1550 void pop(RegionReadState &readState) {
1551 values.resize(values.size() - readState.numValues);
1552 nextValueIDs.pop_back();
1556 std::vector<Value> values;
1575 LazyLoadableOpsInfo lazyLoadableOps;
1576 LazyLoadableOpsMap lazyLoadableOpsMap;
1580 AttrTypeReader attrTypeReader;
1583 uint64_t version = 0;
1590 llvm::StringMap<BytecodeDialect *> dialectsMap;
1594 ResourceSectionReader resourceReader;
1601 StringSectionReader stringReader;
1604 PropertiesSectionReader propertiesReader;
1607 std::vector<ValueScope> valueScopes;
1614 Block forwardRefOps;
1618 Block openForwardRefOps;
1624 llvm::MemoryBufferRef buffer;
1628 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef;
1633 EncodingReader reader(buffer.getBuffer(), fileLoc);
1634 this->lazyOpsCallback = lazyOpsCallback;
1635 auto resetlazyOpsCallback =
1636 llvm::make_scope_exit([&] { this->lazyOpsCallback =
nullptr; });
1639 if (failed(reader.skipBytes(StringRef(
"ML\xefR").size())))
1642 if (failed(parseVersion(reader)) ||
1643 failed(reader.parseNullTerminatedString(producer)))
1649 diag.attachNote() <<
"in bytecode version " << version
1650 <<
" produced by: " << producer;
1655 std::optional<ArrayRef<uint8_t>>
1657 while (!reader.empty()) {
1661 if (failed(reader.parseSection(sectionID, sectionData)))
1665 if (sectionDatas[sectionID]) {
1666 return reader.emitError(
"duplicate top-level section: ",
1669 sectionDatas[sectionID] = sectionData;
1675 return reader.emitError(
"missing data for top-level section: ",
1681 if (failed(stringReader.initialize(
1687 failed(propertiesReader.initialize(
1696 if (failed(parseResourceSection(
1702 if (failed(attrTypeReader.initialize(
1711 LogicalResult BytecodeReader::Impl::parseVersion(EncodingReader &reader) {
1712 if (failed(reader.parseVarInt(version)))
1718 if (version < minSupportedVersion) {
1719 return reader.emitError(
"bytecode version ", version,
1720 " is older than the current version of ",
1721 currentVersion,
", and upgrade is not supported");
1723 if (version > currentVersion) {
1724 return reader.emitError(
"bytecode version ", version,
1725 " is newer than the current version ",
1730 lazyLoading =
false;
1738 LogicalResult BytecodeDialect::load(
const DialectReader &reader,
1744 return reader.emitError(
"dialect '")
1746 <<
"' is unknown. If this is intended, please call "
1747 "allowUnregisteredDialects() on the MLIRContext, or use "
1748 "-allow-unregistered-dialect with the MLIR tool used.";
1750 dialect = loadedDialect;
1756 if (!versionBuffer.empty()) {
1758 return reader.emitError(
"dialect '")
1760 <<
"' does not implement the bytecode interface, "
1761 "but found a version entry";
1762 EncodingReader encReader(versionBuffer, reader.getLoc());
1763 DialectReader versionReader = reader.withEncodingReader(encReader);
1764 loadedVersion = interface->readVersion(versionReader);
1773 EncodingReader sectionReader(sectionData, fileLoc);
1776 uint64_t numDialects;
1777 if (failed(sectionReader.parseVarInt(numDialects)))
1779 dialects.resize(numDialects);
1782 for (uint64_t i = 0; i < numDialects; ++i) {
1783 dialects[i] = std::make_unique<BytecodeDialect>();
1787 if (failed(stringReader.parseString(sectionReader, dialects[i]->name)))
1793 uint64_t dialectNameIdx;
1794 bool versionAvailable;
1795 if (failed(sectionReader.parseVarIntWithFlag(dialectNameIdx,
1798 if (failed(stringReader.parseStringAtIndex(sectionReader, dialectNameIdx,
1799 dialects[i]->name)))
1801 if (versionAvailable) {
1803 if (failed(sectionReader.parseSection(sectionID,
1804 dialects[i]->versionBuffer)))
1807 emitError(fileLoc,
"expected dialect version section");
1811 dialectsMap[dialects[i]->name] = dialects[i].get();
1815 auto parseOpName = [&](BytecodeDialect *dialect) {
1817 std::optional<bool> wasRegistered;
1821 if (failed(stringReader.parseString(sectionReader, opName)))
1824 bool wasRegisteredFlag;
1825 if (failed(stringReader.parseStringWithFlag(sectionReader, opName,
1826 wasRegisteredFlag)))
1828 wasRegistered = wasRegisteredFlag;
1830 opNames.emplace_back(dialect, opName, wasRegistered);
1837 if (failed(sectionReader.parseVarInt(numOps)))
1839 opNames.reserve(numOps);
1841 while (!sectionReader.empty())
1847 FailureOr<OperationName>
1848 BytecodeReader::Impl::parseOpName(EncodingReader &reader,
1849 std::optional<bool> &wasRegistered) {
1850 BytecodeOperationName *opName =
nullptr;
1851 if (failed(
parseEntry(reader, opNames, opName,
"operation name")))
1853 wasRegistered = opName->wasRegistered;
1856 if (!opName->opName) {
1861 if (opName->name.empty()) {
1862 opName->opName.emplace(opName->dialect->name,
getContext());
1865 DialectReader dialectReader(attrTypeReader, stringReader, resourceReader,
1866 dialectsMap, reader, version);
1867 if (failed(opName->dialect->load(dialectReader,
getContext())))
1869 opName->opName.emplace((opName->dialect->name +
"." + opName->name).str(),
1873 return *opName->opName;
1880 LogicalResult BytecodeReader::Impl::parseResourceSection(
1884 if (resourceData.has_value() != resourceOffsetData.has_value()) {
1885 if (resourceOffsetData)
1886 return emitError(fileLoc,
"unexpected resource offset section when "
1887 "resource section is not present");
1890 "expected resource offset section when resource section is present");
1898 DialectReader dialectReader(attrTypeReader, stringReader, resourceReader,
1899 dialectsMap, reader, version);
1900 return resourceReader.initialize(fileLoc,
config, dialects, stringReader,
1901 *resourceData, *resourceOffsetData,
1902 dialectReader, bufferOwnerRef);
1909 FailureOr<BytecodeReader::Impl::UseListMapT>
1910 BytecodeReader::Impl::parseUseListOrderForRange(EncodingReader &reader,
1911 uint64_t numResults) {
1913 uint64_t numValuesToRead = 1;
1914 if (numResults > 1 && failed(reader.parseVarInt(numValuesToRead)))
1917 for (
size_t valueIdx = 0; valueIdx < numValuesToRead; valueIdx++) {
1918 uint64_t resultIdx = 0;
1919 if (numResults > 1 && failed(reader.parseVarInt(resultIdx)))
1923 bool indexPairEncoding;
1924 if (failed(reader.parseVarIntWithFlag(numValues, indexPairEncoding)))
1928 for (
size_t idx = 0; idx < numValues; idx++) {
1930 if (failed(reader.parseVarInt(index)))
1932 useListOrders.push_back(index);
1936 map.try_emplace(resultIdx, UseListOrderStorage(indexPairEncoding,
1937 std::move(useListOrders)));
1948 LogicalResult BytecodeReader::Impl::sortUseListOrder(
Value value) {
1953 bool hasIncomingOrder =
1958 bool alreadySorted =
true;
1965 item.value(), operationIDs.at(item.value().getOwner()));
1966 alreadySorted &= prevID > currentID;
1967 currentOrder.push_back({item.index(), currentID});
1973 if (alreadySorted && !hasIncomingOrder)
1980 currentOrder.begin(), currentOrder.end(),
1981 [](
auto elem1,
auto elem2) { return elem1.second > elem2.second; });
1983 if (!hasIncomingOrder) {
1993 UseListOrderStorage customOrder =
2001 if (customOrder.isIndexPairEncoding) {
2003 if (shuffle.size() & 1)
2008 std::iota(newShuffle.begin(), newShuffle.end(), idx);
2009 for (idx = 0; idx < shuffle.size(); idx += 2)
2010 newShuffle[shuffle[idx]] = shuffle[idx + 1];
2012 shuffle = std::move(newShuffle);
2019 uint64_t accumulator = 0;
2020 for (
const auto &elem : shuffle) {
2021 if (!set.insert(elem).second)
2023 accumulator += elem;
2025 if (numUses != shuffle.size() ||
2026 accumulator != (((numUses - 1) * numUses) >> 1))
2032 currentOrder, [&](
auto item) {
return shuffle[item.first]; }));
2037 LogicalResult BytecodeReader::Impl::processUseLists(
Operation *topLevelOp) {
2041 unsigned operationID = 0;
2043 [&](
Operation *op) { operationIDs.try_emplace(op, operationID++); });
2045 auto blockWalk = topLevelOp->
walk([
this](
Block *block) {
2047 if (failed(sortUseListOrder(arg)))
2054 if (failed(sortUseListOrder(result)))
2059 return failure(blockWalk.wasInterrupted() || resultWalk.wasInterrupted());
2069 EncodingReader reader(sectionData, fileLoc);
2072 std::vector<RegionReadState> regionStack;
2076 regionStack.emplace_back(*moduleOp, &reader,
true);
2077 regionStack.back().curBlocks.push_back(moduleOp->getBody());
2078 regionStack.back().curBlock = regionStack.back().curRegion->begin();
2079 if (failed(parseBlockHeader(reader, regionStack.back())))
2081 valueScopes.emplace_back();
2082 valueScopes.back().push(regionStack.back());
2085 while (!regionStack.empty())
2086 if (failed(
parseRegions(regionStack, regionStack.back())))
2088 if (!forwardRefOps.empty()) {
2089 return reader.emitError(
2090 "not all forward unresolved forward operand references");
2094 if (failed(processUseLists(*moduleOp)))
2095 return reader.emitError(
2096 "parsed use-list orders were invalid and could not be applied");
2099 for (
const std::unique_ptr<BytecodeDialect> &byteCodeDialect : dialects) {
2102 if (!byteCodeDialect->loadedVersion)
2104 if (byteCodeDialect->interface &&
2105 failed(byteCodeDialect->interface->upgradeFromVersion(
2106 *moduleOp, *byteCodeDialect->loadedVersion)))
2111 if (
config.shouldVerifyAfterParse() && failed(
verify(*moduleOp)))
2115 auto &parsedOps = moduleOp->getBody()->getOperations();
2117 destOps.splice(destOps.end(), parsedOps, parsedOps.begin(), parsedOps.end());
2123 RegionReadState &readState) {
2127 for (; readState.curRegion != readState.endRegion; ++readState.curRegion) {
2133 if (failed(parseRegion(readState)))
2137 if (readState.curRegion->empty())
2142 EncodingReader &reader = *readState.reader;
2144 while (readState.numOpsRemaining--) {
2147 bool isIsolatedFromAbove =
false;
2148 FailureOr<Operation *> op =
2149 parseOpWithoutRegions(reader, readState, isIsolatedFromAbove);
2157 if ((*op)->getNumRegions()) {
2158 RegionReadState childState(*op, &reader, isIsolatedFromAbove);
2164 if (failed(reader.parseSection(sectionID, sectionData)))
2167 return emitError(fileLoc,
"expected IR section for region");
2168 childState.owningReader =
2169 std::make_unique<EncodingReader>(sectionData, fileLoc);
2170 childState.reader = childState.owningReader.get();
2174 if (lazyLoading && (!lazyOpsCallback || !lazyOpsCallback(*op))) {
2175 lazyLoadableOps.emplace_back(*op, std::move(childState));
2176 lazyLoadableOpsMap.try_emplace(*op,
2177 std::prev(lazyLoadableOps.end()));
2181 regionStack.push_back(std::move(childState));
2184 if (isIsolatedFromAbove)
2185 valueScopes.emplace_back();
2191 if (++readState.curBlock == readState.curRegion->end())
2193 if (failed(parseBlockHeader(reader, readState)))
2198 readState.curBlock = {};
2199 valueScopes.back().pop(readState);
2204 if (readState.isIsolatedFromAbove) {
2205 assert(!valueScopes.empty() &&
"Expect a valueScope after reading region");
2206 valueScopes.pop_back();
2208 assert(!regionStack.empty() &&
"Expect a regionStack after reading region");
2209 regionStack.pop_back();
2213 FailureOr<Operation *>
2214 BytecodeReader::Impl::parseOpWithoutRegions(EncodingReader &reader,
2215 RegionReadState &readState,
2216 bool &isIsolatedFromAbove) {
2218 std::optional<bool> wasRegistered;
2219 FailureOr<OperationName> opName = parseOpName(reader, wasRegistered);
2226 if (failed(reader.parseByte(opMask)))
2240 DictionaryAttr dictAttr;
2251 "Unexpected missing `wasRegistered` opname flag at "
2252 "bytecode version ")
2253 << version <<
" with properties.";
2257 if (wasRegistered) {
2258 DialectReader dialectReader(attrTypeReader, stringReader, resourceReader,
2259 dialectsMap, reader, version);
2261 propertiesReader.read(fileLoc, dialectReader, &*opName, opState)))
2273 uint64_t numResults;
2274 if (failed(reader.parseVarInt(numResults)))
2276 opState.
types.resize(numResults);
2277 for (
int i = 0, e = numResults; i < e; ++i)
2284 uint64_t numOperands;
2285 if (failed(reader.parseVarInt(numOperands)))
2287 opState.
operands.resize(numOperands);
2288 for (
int i = 0, e = numOperands; i < e; ++i)
2289 if (!(opState.
operands[i] = parseOperand(reader)))
2296 if (failed(reader.parseVarInt(numSuccs)))
2299 for (
int i = 0, e = numSuccs; i < e; ++i) {
2308 std::optional<UseListMapT> resultIdxToUseListMap = std::nullopt;
2311 size_t numResults = opState.
types.size();
2312 auto parseResult = parseUseListOrderForRange(reader, numResults);
2313 if (failed(parseResult))
2315 resultIdxToUseListMap = std::move(*parseResult);
2320 uint64_t numRegions;
2321 if (failed(reader.parseVarIntWithFlag(numRegions, isIsolatedFromAbove)))
2324 opState.
regions.reserve(numRegions);
2325 for (
int i = 0, e = numRegions; i < e; ++i)
2326 opState.
regions.push_back(std::make_unique<Region>());
2331 readState.curBlock->push_back(op);
2337 failed(defineValues(reader, op->
getResults())))
2342 if (resultIdxToUseListMap.has_value()) {
2344 if (resultIdxToUseListMap->contains(idx)) {
2346 resultIdxToUseListMap->at(idx));
2353 LogicalResult BytecodeReader::Impl::parseRegion(RegionReadState &readState) {
2354 EncodingReader &reader = *readState.reader;
2358 if (failed(reader.parseVarInt(numBlocks)))
2367 if (failed(reader.parseVarInt(numValues)))
2369 readState.numValues = numValues;
2373 readState.curBlocks.clear();
2374 readState.curBlocks.reserve(numBlocks);
2375 for (uint64_t i = 0; i < numBlocks; ++i) {
2376 readState.curBlocks.push_back(
new Block());
2377 readState.curRegion->push_back(readState.curBlocks.back());
2381 valueScopes.back().push(readState);
2384 readState.curBlock = readState.curRegion->begin();
2385 return parseBlockHeader(reader, readState);
2389 BytecodeReader::Impl::parseBlockHeader(EncodingReader &reader,
2390 RegionReadState &readState) {
2392 if (failed(reader.parseVarIntWithFlag(readState.numOpsRemaining, hasArgs)))
2396 if (hasArgs && failed(parseBlockArguments(reader, &*readState.curBlock)))
2403 uint8_t hasUseListOrders = 0;
2404 if (hasArgs && failed(reader.parseByte(hasUseListOrders)))
2407 if (!hasUseListOrders)
2410 Block &blk = *readState.curBlock;
2411 auto argIdxToUseListMap =
2413 if (failed(argIdxToUseListMap) || argIdxToUseListMap->empty())
2417 if (argIdxToUseListMap->contains(idx))
2419 argIdxToUseListMap->at(idx));
2425 LogicalResult BytecodeReader::Impl::parseBlockArguments(EncodingReader &reader,
2429 if (failed(reader.parseVarInt(numArgs)))
2434 argTypes.reserve(numArgs);
2435 argLocs.reserve(numArgs);
2445 if (failed(reader.parseVarIntWithFlag(typeIdx, hasLoc)) ||
2446 !(argType = attrTypeReader.resolveType(typeIdx)))
2452 if (failed(
parseType(reader, argType)) ||
2456 argTypes.push_back(argType);
2457 argLocs.push_back(argLoc);
2467 Value BytecodeReader::Impl::parseOperand(EncodingReader &reader) {
2468 std::vector<Value> &values = valueScopes.back().values;
2469 Value *value =
nullptr;
2470 if (failed(
parseEntry(reader, values, value,
"value")))
2475 *value = createForwardRef();
2479 LogicalResult BytecodeReader::Impl::defineValues(EncodingReader &reader,
2481 ValueScope &valueScope = valueScopes.back();
2482 std::vector<Value> &values = valueScope.values;
2484 unsigned &valueID = valueScope.nextValueIDs.back();
2485 unsigned valueIDEnd = valueID + newValues.size();
2486 if (valueIDEnd > values.size()) {
2487 return reader.emitError(
2488 "value index range was outside of the expected range for "
2489 "the parent region, got [",
2490 valueID,
", ", valueIDEnd,
"), but the maximum index was ",
2495 for (
unsigned i = 0, e = newValues.size(); i != e; ++i, ++valueID) {
2496 Value newValue = newValues[i];
2499 if (
Value oldValue = std::exchange(values[valueID], newValue)) {
2500 Operation *forwardRefOp = oldValue.getDefiningOp();
2505 assert(forwardRefOp && forwardRefOp->
getBlock() == &forwardRefOps &&
2506 "value index was already defined?");
2508 oldValue.replaceAllUsesWith(newValue);
2509 forwardRefOp->
moveBefore(&openForwardRefOps, openForwardRefOps.end());
2515 Value BytecodeReader::Impl::createForwardRef() {
2518 if (!openForwardRefOps.empty()) {
2519 Operation *op = &openForwardRefOps.back();
2520 op->
moveBefore(&forwardRefOps, forwardRefOps.end());
2524 return forwardRefOps.back().getResult(0);
2535 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef) {
2539 impl = std::make_unique<Impl>(sourceFileLoc,
config, lazyLoading, buffer,
2545 return impl->read(block, lazyOpsCallback);
2549 return impl->getNumOpsToMaterialize();
2553 return impl->isMaterializable(op);
2558 return impl->materialize(op, lazyOpsCallback);
2563 return impl->finalize(shouldMaterialize);
2567 return buffer.getBuffer().starts_with(
"ML\xefR");
2573 static LogicalResult
2576 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef) {
2582 "input buffer is not an MLIR bytecode file");
2586 buffer, bufferOwnerRef);
2587 return reader.
read(block,
nullptr);
2598 *sourceMgr->getMemoryBuffer(sourceMgr->getMainFileID()), block,
config,
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.
static bool isSectionOptional(bytecode::Section::ID sectionID, int version)
Returns true if the given top-level section ID is optional.
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={})
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.
static LogicalResult resolveEntry(EncodingReader &reader, RangeT &entries, uint64_t index, T &entry, StringRef entryStr)
Resolve an index into the given entry list.
static LogicalResult parseEntry(EncodingReader &reader, RangeT &entries, T &entry, StringRef entryStr)
Parse and resolve an index into the given entry list.
static MLIRContext * getContext(OpFoldResult val)
union mlir::linalg::@1203::ArityGroupAndKind::Kind kind
static std::string diag(const llvm::Value &value)
static ParseResult parseRegions(OpAsmParser &parser, OperationState &state, unsigned nRegions=1)
This class represents an opaque handle to a dialect resource entry.
This class represents a single parsed resource entry.
This class represents a processed binary blob of data.
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.
This class represents an instance of a resource parser.
Attributes are known-constant values of operations.
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()
This class is used to read a bytecode buffer and translate it into MLIR.
LogicalResult materializeAll()
Materialize all operations.
LogicalResult read(Block *block, llvm::function_ref< bool(Operation *)> lazyOps)
Read the bytecode defined within buffer into the given block.
bool isMaterializable(Operation *op)
Impl(Location fileLoc, const ParserConfig &config, bool lazyLoading, llvm::MemoryBufferRef buffer, const std::shared_ptr< llvm::SourceMgr > &bufferOwnerRef)
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...
LogicalResult materialize(Operation *op, llvm::function_ref< bool(Operation *)> lazyOpsCallback)
Materialize the provided operation, invoke the lazyOpsCallback on every newly found lazy operation.
int64_t getNumOpsToMaterialize() const
Return the number of ops that haven't been materialized yet.
LogicalResult materialize(Operation *op, llvm::function_ref< bool(Operation *)> lazyOpsCallback=[](Operation *) { return false;})
Materialize the provide operation.
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...
BytecodeReader(llvm::MemoryBufferRef buffer, const ParserConfig &config, bool lazyLoad, const std::shared_ptr< llvm::SourceMgr > &bufferOwnerRef={})
Create a bytecode reader for the given buffer.
int64_t getNumOpsToMaterialize() const
Return the number of ops that haven't been materialized yet.
bool isMaterializable(Operation *op)
Return true if the provided op is materializable.
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,...
This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine.
This class defines a virtual interface for reading a bytecode stream, providing hooks into the byteco...
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
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.
Location objects represent source locations information in MLIR.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext * getContext() const
Return the context this location is uniqued in.
MLIRContext is the top-level object for a collection of MLIR operations.
bool allowsUnregisteredDialects()
Return true if we allow to create operation for unregistered dialects.
T * getOrLoadDialect()
Get (or create) a dialect for the given derived dialect type.
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
T::Concept * getInterface() const
Returns an instance of the concept object for the given interface if it was registered to this operat...
bool isRegistered() const
Return if this operation is registered.
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...
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
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),...
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.
Block * getBlock()
Returns the operation block that contains this operation.
void moveBefore(Operation *existingOp)
Unlink this operation from its current block and insert it right before existingOp which may be in th...
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.
BlockListType::iterator iterator
This diagnostic handler is a simple RAII class that registers and erases a diagnostic handler on a gi...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
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.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
bool use_empty() const
Returns true if this value has no uses.
void 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.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
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.
const FrozenRewritePatternSet GreedyRewriteConfig config
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.
AsmResourceEntryKind
This enum represents the different kinds of resource values.
@ Blob
A blob of data with an accompanying alignment.
LogicalResult readBytecodeFile(llvm::MemoryBufferRef buffer, Block *block, const ParserConfig &config)
Read the operations defined within the given memory buffer, containing MLIR bytecode,...
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
This represents an operation in an abstracted form, suitable for use with the builder APIs.
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.