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 =
2002 if (customOrder.isIndexPairEncoding) {
2004 if (shuffle.size() & 1)
2009 std::iota(newShuffle.begin(), newShuffle.end(), idx);
2010 for (idx = 0; idx < shuffle.size(); idx += 2)
2011 newShuffle[shuffle[idx]] = shuffle[idx + 1];
2013 shuffle = std::move(newShuffle);
2020 uint64_t accumulator = 0;
2021 for (
const auto &elem : shuffle) {
2022 if (!set.insert(elem).second)
2024 accumulator += elem;
2026 if (numUses != shuffle.size() ||
2027 accumulator != (((numUses - 1) * numUses) >> 1))
2033 currentOrder, [&](
auto item) {
return shuffle[item.first]; }));
2038 LogicalResult BytecodeReader::Impl::processUseLists(
Operation *topLevelOp) {
2042 unsigned operationID = 0;
2044 [&](
Operation *op) { operationIDs.try_emplace(op, operationID++); });
2046 auto blockWalk = topLevelOp->
walk([
this](
Block *block) {
2048 if (failed(sortUseListOrder(arg)))
2055 if (failed(sortUseListOrder(result)))
2060 return failure(blockWalk.wasInterrupted() || resultWalk.wasInterrupted());
2070 EncodingReader reader(sectionData, fileLoc);
2073 std::vector<RegionReadState> regionStack;
2077 regionStack.emplace_back(*moduleOp, &reader,
true);
2078 regionStack.back().curBlocks.push_back(moduleOp->getBody());
2079 regionStack.back().curBlock = regionStack.back().curRegion->begin();
2080 if (failed(parseBlockHeader(reader, regionStack.back())))
2082 valueScopes.emplace_back();
2083 valueScopes.back().push(regionStack.back());
2086 while (!regionStack.empty())
2087 if (failed(
parseRegions(regionStack, regionStack.back())))
2089 if (!forwardRefOps.empty()) {
2090 return reader.emitError(
2091 "not all forward unresolved forward operand references");
2095 if (failed(processUseLists(*moduleOp)))
2096 return reader.emitError(
2097 "parsed use-list orders were invalid and could not be applied");
2100 for (
const std::unique_ptr<BytecodeDialect> &byteCodeDialect : dialects) {
2103 if (!byteCodeDialect->loadedVersion)
2105 if (byteCodeDialect->interface &&
2106 failed(byteCodeDialect->interface->upgradeFromVersion(
2107 *moduleOp, *byteCodeDialect->loadedVersion)))
2112 if (
config.shouldVerifyAfterParse() && failed(
verify(*moduleOp)))
2116 auto &parsedOps = moduleOp->getBody()->getOperations();
2118 destOps.splice(destOps.end(), parsedOps, parsedOps.begin(), parsedOps.end());
2124 RegionReadState &readState) {
2128 for (; readState.curRegion != readState.endRegion; ++readState.curRegion) {
2134 if (failed(parseRegion(readState)))
2138 if (readState.curRegion->empty())
2143 EncodingReader &reader = *readState.reader;
2145 while (readState.numOpsRemaining--) {
2148 bool isIsolatedFromAbove =
false;
2149 FailureOr<Operation *> op =
2150 parseOpWithoutRegions(reader, readState, isIsolatedFromAbove);
2158 if ((*op)->getNumRegions()) {
2159 RegionReadState childState(*op, &reader, isIsolatedFromAbove);
2165 if (failed(reader.parseSection(sectionID, sectionData)))
2168 return emitError(fileLoc,
"expected IR section for region");
2169 childState.owningReader =
2170 std::make_unique<EncodingReader>(sectionData, fileLoc);
2171 childState.reader = childState.owningReader.get();
2175 if (lazyLoading && (!lazyOpsCallback || !lazyOpsCallback(*op))) {
2176 lazyLoadableOps.emplace_back(*op, std::move(childState));
2177 lazyLoadableOpsMap.try_emplace(*op,
2178 std::prev(lazyLoadableOps.end()));
2182 regionStack.push_back(std::move(childState));
2185 if (isIsolatedFromAbove)
2186 valueScopes.emplace_back();
2192 if (++readState.curBlock == readState.curRegion->end())
2194 if (failed(parseBlockHeader(reader, readState)))
2199 readState.curBlock = {};
2200 valueScopes.back().pop(readState);
2205 if (readState.isIsolatedFromAbove) {
2206 assert(!valueScopes.empty() &&
"Expect a valueScope after reading region");
2207 valueScopes.pop_back();
2209 assert(!regionStack.empty() &&
"Expect a regionStack after reading region");
2210 regionStack.pop_back();
2214 FailureOr<Operation *>
2215 BytecodeReader::Impl::parseOpWithoutRegions(EncodingReader &reader,
2216 RegionReadState &readState,
2217 bool &isIsolatedFromAbove) {
2219 std::optional<bool> wasRegistered;
2220 FailureOr<OperationName> opName = parseOpName(reader, wasRegistered);
2227 if (failed(reader.parseByte(opMask)))
2241 DictionaryAttr dictAttr;
2252 "Unexpected missing `wasRegistered` opname flag at "
2253 "bytecode version ")
2254 << version <<
" with properties.";
2258 if (wasRegistered) {
2259 DialectReader dialectReader(attrTypeReader, stringReader, resourceReader,
2260 dialectsMap, reader, version);
2262 propertiesReader.read(fileLoc, dialectReader, &*opName, opState)))
2274 uint64_t numResults;
2275 if (failed(reader.parseVarInt(numResults)))
2277 opState.
types.resize(numResults);
2278 for (
int i = 0, e = numResults; i < e; ++i)
2285 uint64_t numOperands;
2286 if (failed(reader.parseVarInt(numOperands)))
2288 opState.
operands.resize(numOperands);
2289 for (
int i = 0, e = numOperands; i < e; ++i)
2290 if (!(opState.
operands[i] = parseOperand(reader)))
2297 if (failed(reader.parseVarInt(numSuccs)))
2300 for (
int i = 0, e = numSuccs; i < e; ++i) {
2309 std::optional<UseListMapT> resultIdxToUseListMap = std::nullopt;
2312 size_t numResults = opState.
types.size();
2313 auto parseResult = parseUseListOrderForRange(reader, numResults);
2314 if (failed(parseResult))
2316 resultIdxToUseListMap = std::move(*parseResult);
2321 uint64_t numRegions;
2322 if (failed(reader.parseVarIntWithFlag(numRegions, isIsolatedFromAbove)))
2325 opState.
regions.reserve(numRegions);
2326 for (
int i = 0, e = numRegions; i < e; ++i)
2327 opState.
regions.push_back(std::make_unique<Region>());
2332 readState.curBlock->push_back(op);
2338 failed(defineValues(reader, op->
getResults())))
2343 if (resultIdxToUseListMap.has_value()) {
2345 if (resultIdxToUseListMap->contains(idx)) {
2347 resultIdxToUseListMap->at(idx));
2354 LogicalResult BytecodeReader::Impl::parseRegion(RegionReadState &readState) {
2355 EncodingReader &reader = *readState.reader;
2359 if (failed(reader.parseVarInt(numBlocks)))
2368 if (failed(reader.parseVarInt(numValues)))
2370 readState.numValues = numValues;
2374 readState.curBlocks.clear();
2375 readState.curBlocks.reserve(numBlocks);
2376 for (uint64_t i = 0; i < numBlocks; ++i) {
2377 readState.curBlocks.push_back(
new Block());
2378 readState.curRegion->push_back(readState.curBlocks.back());
2382 valueScopes.back().push(readState);
2385 readState.curBlock = readState.curRegion->begin();
2386 return parseBlockHeader(reader, readState);
2390 BytecodeReader::Impl::parseBlockHeader(EncodingReader &reader,
2391 RegionReadState &readState) {
2393 if (failed(reader.parseVarIntWithFlag(readState.numOpsRemaining, hasArgs)))
2397 if (hasArgs && failed(parseBlockArguments(reader, &*readState.curBlock)))
2404 uint8_t hasUseListOrders = 0;
2405 if (hasArgs && failed(reader.parseByte(hasUseListOrders)))
2408 if (!hasUseListOrders)
2411 Block &blk = *readState.curBlock;
2412 auto argIdxToUseListMap =
2414 if (failed(argIdxToUseListMap) || argIdxToUseListMap->empty())
2418 if (argIdxToUseListMap->contains(idx))
2420 argIdxToUseListMap->at(idx));
2426 LogicalResult BytecodeReader::Impl::parseBlockArguments(EncodingReader &reader,
2430 if (failed(reader.parseVarInt(numArgs)))
2435 argTypes.reserve(numArgs);
2436 argLocs.reserve(numArgs);
2446 if (failed(reader.parseVarIntWithFlag(typeIdx, hasLoc)) ||
2447 !(argType = attrTypeReader.resolveType(typeIdx)))
2453 if (failed(
parseType(reader, argType)) ||
2457 argTypes.push_back(argType);
2458 argLocs.push_back(argLoc);
2468 Value BytecodeReader::Impl::parseOperand(EncodingReader &reader) {
2469 std::vector<Value> &values = valueScopes.back().values;
2470 Value *value =
nullptr;
2471 if (failed(
parseEntry(reader, values, value,
"value")))
2476 *value = createForwardRef();
2480 LogicalResult BytecodeReader::Impl::defineValues(EncodingReader &reader,
2482 ValueScope &valueScope = valueScopes.back();
2483 std::vector<Value> &values = valueScope.values;
2485 unsigned &valueID = valueScope.nextValueIDs.back();
2486 unsigned valueIDEnd = valueID + newValues.size();
2487 if (valueIDEnd > values.size()) {
2488 return reader.emitError(
2489 "value index range was outside of the expected range for "
2490 "the parent region, got [",
2491 valueID,
", ", valueIDEnd,
"), but the maximum index was ",
2496 for (
unsigned i = 0, e = newValues.size(); i != e; ++i, ++valueID) {
2497 Value newValue = newValues[i];
2500 if (
Value oldValue = std::exchange(values[valueID], newValue)) {
2501 Operation *forwardRefOp = oldValue.getDefiningOp();
2506 assert(forwardRefOp && forwardRefOp->
getBlock() == &forwardRefOps &&
2507 "value index was already defined?");
2509 oldValue.replaceAllUsesWith(newValue);
2510 forwardRefOp->
moveBefore(&openForwardRefOps, openForwardRefOps.end());
2516 Value BytecodeReader::Impl::createForwardRef() {
2519 if (!openForwardRefOps.empty()) {
2520 Operation *op = &openForwardRefOps.back();
2521 op->
moveBefore(&forwardRefOps, forwardRefOps.end());
2525 return forwardRefOps.back().getResult(0);
2536 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef) {
2540 impl = std::make_unique<Impl>(sourceFileLoc,
config, lazyLoading, buffer,
2546 return impl->read(block, lazyOpsCallback);
2550 return impl->getNumOpsToMaterialize();
2554 return impl->isMaterializable(op);
2559 return impl->materialize(op, lazyOpsCallback);
2564 return impl->finalize(shouldMaterialize);
2568 return buffer.getBuffer().starts_with(
"ML\xefR");
2574 static LogicalResult
2577 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef) {
2583 "input buffer is not an MLIR bytecode file");
2587 buffer, bufferOwnerRef);
2588 return reader.
read(block,
nullptr);
2599 *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::@1193::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.
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.