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 "
575 <<
toString(kind) <<
" entry instead";
578 if (failed(reader.parseByte(value)))
582 FailureOr<std::string> parseAsString() const final {
584 return emitError() <<
"expected a string resource entry, but found a "
585 <<
toString(kind) <<
" entry instead";
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 "
597 <<
toString(kind) <<
" entry instead";
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;
1737 LogicalResult BytecodeDialect::load(
const DialectReader &reader,
1743 return reader.emitError(
"dialect '")
1745 <<
"' is unknown. If this is intended, please call "
1746 "allowUnregisteredDialects() on the MLIRContext, or use "
1747 "-allow-unregistered-dialect with the MLIR tool used.";
1749 dialect = loadedDialect;
1755 if (!versionBuffer.empty()) {
1757 return reader.emitError(
"dialect '")
1759 <<
"' does not implement the bytecode interface, "
1760 "but found a version entry";
1761 EncodingReader encReader(versionBuffer, reader.getLoc());
1762 DialectReader versionReader = reader.withEncodingReader(encReader);
1763 loadedVersion = interface->readVersion(versionReader);
1772 EncodingReader sectionReader(sectionData, fileLoc);
1775 uint64_t numDialects;
1776 if (failed(sectionReader.parseVarInt(numDialects)))
1778 dialects.resize(numDialects);
1781 for (uint64_t i = 0; i < numDialects; ++i) {
1782 dialects[i] = std::make_unique<BytecodeDialect>();
1786 if (failed(stringReader.parseString(sectionReader, dialects[i]->name)))
1792 uint64_t dialectNameIdx;
1793 bool versionAvailable;
1794 if (failed(sectionReader.parseVarIntWithFlag(dialectNameIdx,
1797 if (failed(stringReader.parseStringAtIndex(sectionReader, dialectNameIdx,
1798 dialects[i]->name)))
1800 if (versionAvailable) {
1802 if (failed(sectionReader.parseSection(sectionID,
1803 dialects[i]->versionBuffer)))
1806 emitError(fileLoc,
"expected dialect version section");
1810 dialectsMap[dialects[i]->name] = dialects[i].get();
1814 auto parseOpName = [&](BytecodeDialect *dialect) {
1816 std::optional<bool> wasRegistered;
1820 if (failed(stringReader.parseString(sectionReader, opName)))
1823 bool wasRegisteredFlag;
1824 if (failed(stringReader.parseStringWithFlag(sectionReader, opName,
1825 wasRegisteredFlag)))
1827 wasRegistered = wasRegisteredFlag;
1829 opNames.emplace_back(dialect, opName, wasRegistered);
1836 if (failed(sectionReader.parseVarInt(numOps)))
1838 opNames.reserve(numOps);
1840 while (!sectionReader.empty())
1846 FailureOr<OperationName>
1847 BytecodeReader::Impl::parseOpName(EncodingReader &reader,
1848 std::optional<bool> &wasRegistered) {
1849 BytecodeOperationName *opName =
nullptr;
1850 if (failed(
parseEntry(reader, opNames, opName,
"operation name")))
1852 wasRegistered = opName->wasRegistered;
1855 if (!opName->opName) {
1860 if (opName->name.empty()) {
1861 opName->opName.emplace(opName->dialect->name,
getContext());
1864 DialectReader dialectReader(attrTypeReader, stringReader, resourceReader,
1865 dialectsMap, reader, version);
1866 if (failed(opName->dialect->load(dialectReader,
getContext())))
1868 opName->opName.emplace((opName->dialect->name +
"." + opName->name).str(),
1872 return *opName->opName;
1878 LogicalResult BytecodeReader::Impl::parseResourceSection(
1882 if (resourceData.has_value() != resourceOffsetData.has_value()) {
1883 if (resourceOffsetData)
1884 return emitError(fileLoc,
"unexpected resource offset section when "
1885 "resource section is not present");
1888 "expected resource offset section when resource section is present");
1896 DialectReader dialectReader(attrTypeReader, stringReader, resourceReader,
1897 dialectsMap, reader, version);
1898 return resourceReader.initialize(fileLoc, config, dialects, stringReader,
1899 *resourceData, *resourceOffsetData,
1900 dialectReader, bufferOwnerRef);
1906 FailureOr<BytecodeReader::Impl::UseListMapT>
1907 BytecodeReader::Impl::parseUseListOrderForRange(EncodingReader &reader,
1908 uint64_t numResults) {
1910 uint64_t numValuesToRead = 1;
1911 if (numResults > 1 && failed(reader.parseVarInt(numValuesToRead)))
1914 for (
size_t valueIdx = 0; valueIdx < numValuesToRead; valueIdx++) {
1915 uint64_t resultIdx = 0;
1916 if (numResults > 1 && failed(reader.parseVarInt(resultIdx)))
1920 bool indexPairEncoding;
1921 if (failed(reader.parseVarIntWithFlag(numValues, indexPairEncoding)))
1925 for (
size_t idx = 0; idx < numValues; idx++) {
1927 if (failed(reader.parseVarInt(index)))
1929 useListOrders.push_back(index);
1933 map.try_emplace(resultIdx, UseListOrderStorage(indexPairEncoding,
1934 std::move(useListOrders)));
1945 LogicalResult BytecodeReader::Impl::sortUseListOrder(
Value value) {
1950 bool hasIncomingOrder =
1955 bool alreadySorted =
true;
1962 item.value(), operationIDs.at(item.value().getOwner()));
1963 alreadySorted &= prevID > currentID;
1964 currentOrder.push_back({item.index(), currentID});
1970 if (alreadySorted && !hasIncomingOrder)
1977 currentOrder.begin(), currentOrder.end(),
1978 [](
auto elem1,
auto elem2) { return elem1.second > elem2.second; });
1980 if (!hasIncomingOrder) {
1985 llvm::map_range(currentOrder, [&](
auto item) {
return item.first; }));
1991 UseListOrderStorage customOrder =
2000 if (customOrder.isIndexPairEncoding) {
2002 if (shuffle.size() & 1)
2007 std::iota(newShuffle.begin(), newShuffle.end(), idx);
2008 for (idx = 0; idx < shuffle.size(); idx += 2)
2009 newShuffle[shuffle[idx]] = shuffle[idx + 1];
2011 shuffle = std::move(newShuffle);
2018 uint64_t accumulator = 0;
2019 for (
const auto &elem : shuffle) {
2020 if (!set.insert(elem).second)
2022 accumulator += elem;
2024 if (numUses != shuffle.size() ||
2025 accumulator != (((numUses - 1) * numUses) >> 1))
2031 currentOrder, [&](
auto item) {
return shuffle[item.first]; }));
2036 LogicalResult BytecodeReader::Impl::processUseLists(
Operation *topLevelOp) {
2040 unsigned operationID = 0;
2042 [&](
Operation *op) { operationIDs.try_emplace(op, operationID++); });
2044 auto blockWalk = topLevelOp->
walk([
this](
Block *block) {
2046 if (failed(sortUseListOrder(arg)))
2053 if (failed(sortUseListOrder(result)))
2058 return failure(blockWalk.wasInterrupted() || resultWalk.wasInterrupted());
2067 EncodingReader reader(sectionData, fileLoc);
2070 std::vector<RegionReadState> regionStack;
2074 regionStack.emplace_back(*moduleOp, &reader,
true);
2075 regionStack.back().curBlocks.push_back(moduleOp->getBody());
2076 regionStack.back().curBlock = regionStack.back().curRegion->begin();
2077 if (failed(parseBlockHeader(reader, regionStack.back())))
2079 valueScopes.emplace_back();
2080 valueScopes.back().push(regionStack.back());
2083 while (!regionStack.empty())
2084 if (failed(
parseRegions(regionStack, regionStack.back())))
2086 if (!forwardRefOps.empty()) {
2087 return reader.emitError(
2088 "not all forward unresolved forward operand references");
2092 if (failed(processUseLists(*moduleOp)))
2093 return reader.emitError(
2094 "parsed use-list orders were invalid and could not be applied");
2097 for (
const std::unique_ptr<BytecodeDialect> &byteCodeDialect : dialects) {
2100 if (!byteCodeDialect->loadedVersion)
2102 if (byteCodeDialect->interface &&
2103 failed(byteCodeDialect->interface->upgradeFromVersion(
2104 *moduleOp, *byteCodeDialect->loadedVersion)))
2113 auto &parsedOps = moduleOp->getBody()->getOperations();
2115 destOps.splice(destOps.end(), parsedOps, parsedOps.begin(), parsedOps.end());
2121 RegionReadState &readState) {
2125 for (; readState.curRegion != readState.endRegion; ++readState.curRegion) {
2131 if (failed(parseRegion(readState)))
2135 if (readState.curRegion->empty())
2140 EncodingReader &reader = *readState.reader;
2142 while (readState.numOpsRemaining--) {
2145 bool isIsolatedFromAbove =
false;
2146 FailureOr<Operation *> op =
2147 parseOpWithoutRegions(reader, readState, isIsolatedFromAbove);
2155 if ((*op)->getNumRegions()) {
2156 RegionReadState childState(*op, &reader, isIsolatedFromAbove);
2162 if (failed(reader.parseSection(sectionID, sectionData)))
2165 return emitError(fileLoc,
"expected IR section for region");
2166 childState.owningReader =
2167 std::make_unique<EncodingReader>(sectionData, fileLoc);
2168 childState.reader = childState.owningReader.get();
2172 if (lazyLoading && (!lazyOpsCallback || !lazyOpsCallback(*op))) {
2173 lazyLoadableOps.emplace_back(*op, std::move(childState));
2174 lazyLoadableOpsMap.try_emplace(*op,
2175 std::prev(lazyLoadableOps.end()));
2179 regionStack.push_back(std::move(childState));
2182 if (isIsolatedFromAbove)
2183 valueScopes.emplace_back();
2189 if (++readState.curBlock == readState.curRegion->end())
2191 if (failed(parseBlockHeader(reader, readState)))
2196 readState.curBlock = {};
2197 valueScopes.back().pop(readState);
2202 if (readState.isIsolatedFromAbove) {
2203 assert(!valueScopes.empty() &&
"Expect a valueScope after reading region");
2204 valueScopes.pop_back();
2206 assert(!regionStack.empty() &&
"Expect a regionStack after reading region");
2207 regionStack.pop_back();
2211 FailureOr<Operation *>
2212 BytecodeReader::Impl::parseOpWithoutRegions(EncodingReader &reader,
2213 RegionReadState &readState,
2214 bool &isIsolatedFromAbove) {
2216 std::optional<bool> wasRegistered;
2217 FailureOr<OperationName> opName = parseOpName(reader, wasRegistered);
2224 if (failed(reader.parseByte(opMask)))
2238 DictionaryAttr dictAttr;
2249 "Unexpected missing `wasRegistered` opname flag at "
2250 "bytecode version ")
2251 << version <<
" with properties.";
2255 if (wasRegistered) {
2256 DialectReader dialectReader(attrTypeReader, stringReader, resourceReader,
2257 dialectsMap, reader, version);
2259 propertiesReader.read(fileLoc, dialectReader, &*opName, opState)))
2271 uint64_t numResults;
2272 if (failed(reader.parseVarInt(numResults)))
2274 opState.
types.resize(numResults);
2275 for (
int i = 0, e = numResults; i < e; ++i)
2282 uint64_t numOperands;
2283 if (failed(reader.parseVarInt(numOperands)))
2285 opState.
operands.resize(numOperands);
2286 for (
int i = 0, e = numOperands; i < e; ++i)
2287 if (!(opState.
operands[i] = parseOperand(reader)))
2294 if (failed(reader.parseVarInt(numSuccs)))
2297 for (
int i = 0, e = numSuccs; i < e; ++i) {
2306 std::optional<UseListMapT> resultIdxToUseListMap = std::nullopt;
2309 size_t numResults = opState.
types.size();
2310 auto parseResult = parseUseListOrderForRange(reader, numResults);
2311 if (failed(parseResult))
2313 resultIdxToUseListMap = std::move(*parseResult);
2318 uint64_t numRegions;
2319 if (failed(reader.parseVarIntWithFlag(numRegions, isIsolatedFromAbove)))
2322 opState.
regions.reserve(numRegions);
2323 for (
int i = 0, e = numRegions; i < e; ++i)
2324 opState.
regions.push_back(std::make_unique<Region>());
2329 readState.curBlock->push_back(op);
2335 failed(defineValues(reader, op->
getResults())))
2340 if (resultIdxToUseListMap.has_value()) {
2342 if (resultIdxToUseListMap->contains(idx)) {
2344 resultIdxToUseListMap->at(idx));
2351 LogicalResult BytecodeReader::Impl::parseRegion(RegionReadState &readState) {
2352 EncodingReader &reader = *readState.reader;
2356 if (failed(reader.parseVarInt(numBlocks)))
2365 if (failed(reader.parseVarInt(numValues)))
2367 readState.numValues = numValues;
2371 readState.curBlocks.clear();
2372 readState.curBlocks.reserve(numBlocks);
2373 for (uint64_t i = 0; i < numBlocks; ++i) {
2374 readState.curBlocks.push_back(
new Block());
2375 readState.curRegion->push_back(readState.curBlocks.back());
2379 valueScopes.back().push(readState);
2382 readState.curBlock = readState.curRegion->begin();
2383 return parseBlockHeader(reader, readState);
2387 BytecodeReader::Impl::parseBlockHeader(EncodingReader &reader,
2388 RegionReadState &readState) {
2390 if (failed(reader.parseVarIntWithFlag(readState.numOpsRemaining, hasArgs)))
2394 if (hasArgs && failed(parseBlockArguments(reader, &*readState.curBlock)))
2401 uint8_t hasUseListOrders = 0;
2402 if (hasArgs && failed(reader.parseByte(hasUseListOrders)))
2405 if (!hasUseListOrders)
2408 Block &blk = *readState.curBlock;
2409 auto argIdxToUseListMap =
2411 if (failed(argIdxToUseListMap) || argIdxToUseListMap->empty())
2415 if (argIdxToUseListMap->contains(idx))
2417 argIdxToUseListMap->at(idx));
2423 LogicalResult BytecodeReader::Impl::parseBlockArguments(EncodingReader &reader,
2427 if (failed(reader.parseVarInt(numArgs)))
2432 argTypes.reserve(numArgs);
2433 argLocs.reserve(numArgs);
2443 if (failed(reader.parseVarIntWithFlag(typeIdx, hasLoc)) ||
2444 !(argType = attrTypeReader.resolveType(typeIdx)))
2450 if (failed(
parseType(reader, argType)) ||
2454 argTypes.push_back(argType);
2455 argLocs.push_back(argLoc);
2464 Value BytecodeReader::Impl::parseOperand(EncodingReader &reader) {
2465 std::vector<Value> &values = valueScopes.back().values;
2466 Value *value =
nullptr;
2467 if (failed(
parseEntry(reader, values, value,
"value")))
2472 *value = createForwardRef();
2476 LogicalResult BytecodeReader::Impl::defineValues(EncodingReader &reader,
2478 ValueScope &valueScope = valueScopes.back();
2479 std::vector<Value> &values = valueScope.values;
2481 unsigned &valueID = valueScope.nextValueIDs.back();
2482 unsigned valueIDEnd = valueID + newValues.size();
2483 if (valueIDEnd > values.size()) {
2484 return reader.emitError(
2485 "value index range was outside of the expected range for "
2486 "the parent region, got [",
2487 valueID,
", ", valueIDEnd,
"), but the maximum index was ",
2492 for (
unsigned i = 0, e = newValues.size(); i != e; ++i, ++valueID) {
2493 Value newValue = newValues[i];
2496 if (
Value oldValue = std::exchange(values[valueID], newValue)) {
2497 Operation *forwardRefOp = oldValue.getDefiningOp();
2502 assert(forwardRefOp && forwardRefOp->
getBlock() == &forwardRefOps &&
2503 "value index was already defined?");
2505 oldValue.replaceAllUsesWith(newValue);
2506 forwardRefOp->
moveBefore(&openForwardRefOps, openForwardRefOps.end());
2512 Value BytecodeReader::Impl::createForwardRef() {
2515 if (!openForwardRefOps.empty()) {
2516 Operation *op = &openForwardRefOps.back();
2517 op->
moveBefore(&forwardRefOps, forwardRefOps.end());
2521 return forwardRefOps.back().getResult(0);
2531 llvm::MemoryBufferRef buffer,
const ParserConfig &config,
bool lazyLoading,
2532 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef) {
2536 impl = std::make_unique<Impl>(sourceFileLoc, config, lazyLoading, buffer,
2542 return impl->read(block, lazyOpsCallback);
2546 return impl->getNumOpsToMaterialize();
2550 return impl->isMaterializable(op);
2555 return impl->materialize(op, lazyOpsCallback);
2560 return impl->finalize(shouldMaterialize);
2564 return buffer.getBuffer().starts_with(
"ML\xefR");
2570 static LogicalResult
2573 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef) {
2579 "input buffer is not an MLIR bytecode file");
2583 buffer, bufferOwnerRef);
2584 return reader.
read(block,
nullptr);
2595 *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)
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...
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.
bool shouldVerifyAfterParse() const
Returns if the parser should verify the IR after parsing.
MLIRContext * getContext() const
Return the MLIRContext to be used when parsing.
AsmResourceParser * getResourceParser(StringRef name) const
Return the resource parser registered to the given name, or nullptr if no parser with name is registe...
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.
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.