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.contains(elem))
2022 accumulator += elem;
2025 if (numUses != shuffle.size() ||
2026 accumulator != (((numUses - 1) * numUses) >> 1))
2032 currentOrder, [&](
auto item) {
return shuffle[item.first]; }));
2037 LogicalResult BytecodeReader::Impl::processUseLists(
Operation *topLevelOp) {
2041 unsigned operationID = 0;
2043 [&](
Operation *op) { operationIDs.try_emplace(op, operationID++); });
2045 auto blockWalk = topLevelOp->
walk([
this](
Block *block) {
2047 if (failed(sortUseListOrder(arg)))
2054 if (failed(sortUseListOrder(result)))
2059 return failure(blockWalk.wasInterrupted() || resultWalk.wasInterrupted());
2068 EncodingReader reader(sectionData, fileLoc);
2071 std::vector<RegionReadState> regionStack;
2075 regionStack.emplace_back(*moduleOp, &reader,
true);
2076 regionStack.back().curBlocks.push_back(moduleOp->getBody());
2077 regionStack.back().curBlock = regionStack.back().curRegion->begin();
2078 if (failed(parseBlockHeader(reader, regionStack.back())))
2080 valueScopes.emplace_back();
2081 valueScopes.back().push(regionStack.back());
2084 while (!regionStack.empty())
2085 if (failed(
parseRegions(regionStack, regionStack.back())))
2087 if (!forwardRefOps.empty()) {
2088 return reader.emitError(
2089 "not all forward unresolved forward operand references");
2093 if (failed(processUseLists(*moduleOp)))
2094 return reader.emitError(
2095 "parsed use-list orders were invalid and could not be applied");
2098 for (
const std::unique_ptr<BytecodeDialect> &byteCodeDialect : dialects) {
2101 if (!byteCodeDialect->loadedVersion)
2103 if (byteCodeDialect->interface &&
2104 failed(byteCodeDialect->interface->upgradeFromVersion(
2105 *moduleOp, *byteCodeDialect->loadedVersion)))
2114 auto &parsedOps = moduleOp->getBody()->getOperations();
2116 destOps.splice(destOps.end(), parsedOps, parsedOps.begin(), parsedOps.end());
2122 RegionReadState &readState) {
2126 for (; readState.curRegion != readState.endRegion; ++readState.curRegion) {
2132 if (failed(parseRegion(readState)))
2136 if (readState.curRegion->empty())
2141 EncodingReader &reader = *readState.reader;
2143 while (readState.numOpsRemaining--) {
2146 bool isIsolatedFromAbove =
false;
2147 FailureOr<Operation *> op =
2148 parseOpWithoutRegions(reader, readState, isIsolatedFromAbove);
2156 if ((*op)->getNumRegions()) {
2157 RegionReadState childState(*op, &reader, isIsolatedFromAbove);
2163 if (failed(reader.parseSection(sectionID, sectionData)))
2166 return emitError(fileLoc,
"expected IR section for region");
2167 childState.owningReader =
2168 std::make_unique<EncodingReader>(sectionData, fileLoc);
2169 childState.reader = childState.owningReader.get();
2173 if (lazyLoading && (!lazyOpsCallback || !lazyOpsCallback(*op))) {
2174 lazyLoadableOps.emplace_back(*op, std::move(childState));
2175 lazyLoadableOpsMap.try_emplace(*op,
2176 std::prev(lazyLoadableOps.end()));
2180 regionStack.push_back(std::move(childState));
2183 if (isIsolatedFromAbove)
2184 valueScopes.emplace_back();
2190 if (++readState.curBlock == readState.curRegion->end())
2192 if (failed(parseBlockHeader(reader, readState)))
2197 readState.curBlock = {};
2198 valueScopes.back().pop(readState);
2203 if (readState.isIsolatedFromAbove) {
2204 assert(!valueScopes.empty() &&
"Expect a valueScope after reading region");
2205 valueScopes.pop_back();
2207 assert(!regionStack.empty() &&
"Expect a regionStack after reading region");
2208 regionStack.pop_back();
2212 FailureOr<Operation *>
2213 BytecodeReader::Impl::parseOpWithoutRegions(EncodingReader &reader,
2214 RegionReadState &readState,
2215 bool &isIsolatedFromAbove) {
2217 std::optional<bool> wasRegistered;
2218 FailureOr<OperationName> opName = parseOpName(reader, wasRegistered);
2225 if (failed(reader.parseByte(opMask)))
2239 DictionaryAttr dictAttr;
2250 "Unexpected missing `wasRegistered` opname flag at "
2251 "bytecode version ")
2252 << version <<
" with properties.";
2256 if (wasRegistered) {
2257 DialectReader dialectReader(attrTypeReader, stringReader, resourceReader,
2258 dialectsMap, reader, version);
2260 propertiesReader.read(fileLoc, dialectReader, &*opName, opState)))
2272 uint64_t numResults;
2273 if (failed(reader.parseVarInt(numResults)))
2275 opState.
types.resize(numResults);
2276 for (
int i = 0, e = numResults; i < e; ++i)
2283 uint64_t numOperands;
2284 if (failed(reader.parseVarInt(numOperands)))
2286 opState.
operands.resize(numOperands);
2287 for (
int i = 0, e = numOperands; i < e; ++i)
2288 if (!(opState.
operands[i] = parseOperand(reader)))
2295 if (failed(reader.parseVarInt(numSuccs)))
2298 for (
int i = 0, e = numSuccs; i < e; ++i) {
2307 std::optional<UseListMapT> resultIdxToUseListMap = std::nullopt;
2310 size_t numResults = opState.
types.size();
2311 auto parseResult = parseUseListOrderForRange(reader, numResults);
2312 if (failed(parseResult))
2314 resultIdxToUseListMap = std::move(*parseResult);
2319 uint64_t numRegions;
2320 if (failed(reader.parseVarIntWithFlag(numRegions, isIsolatedFromAbove)))
2323 opState.
regions.reserve(numRegions);
2324 for (
int i = 0, e = numRegions; i < e; ++i)
2325 opState.
regions.push_back(std::make_unique<Region>());
2330 readState.curBlock->push_back(op);
2336 failed(defineValues(reader, op->
getResults())))
2341 if (resultIdxToUseListMap.has_value()) {
2343 if (resultIdxToUseListMap->contains(idx)) {
2345 resultIdxToUseListMap->at(idx));
2352 LogicalResult BytecodeReader::Impl::parseRegion(RegionReadState &readState) {
2353 EncodingReader &reader = *readState.reader;
2357 if (failed(reader.parseVarInt(numBlocks)))
2366 if (failed(reader.parseVarInt(numValues)))
2368 readState.numValues = numValues;
2372 readState.curBlocks.clear();
2373 readState.curBlocks.reserve(numBlocks);
2374 for (uint64_t i = 0; i < numBlocks; ++i) {
2375 readState.curBlocks.push_back(
new Block());
2376 readState.curRegion->push_back(readState.curBlocks.back());
2380 valueScopes.back().push(readState);
2383 readState.curBlock = readState.curRegion->begin();
2384 return parseBlockHeader(reader, readState);
2388 BytecodeReader::Impl::parseBlockHeader(EncodingReader &reader,
2389 RegionReadState &readState) {
2391 if (failed(reader.parseVarIntWithFlag(readState.numOpsRemaining, hasArgs)))
2395 if (hasArgs && failed(parseBlockArguments(reader, &*readState.curBlock)))
2402 uint8_t hasUseListOrders = 0;
2403 if (hasArgs && failed(reader.parseByte(hasUseListOrders)))
2406 if (!hasUseListOrders)
2409 Block &blk = *readState.curBlock;
2410 auto argIdxToUseListMap =
2412 if (failed(argIdxToUseListMap) || argIdxToUseListMap->empty())
2416 if (argIdxToUseListMap->contains(idx))
2418 argIdxToUseListMap->at(idx));
2424 LogicalResult BytecodeReader::Impl::parseBlockArguments(EncodingReader &reader,
2428 if (failed(reader.parseVarInt(numArgs)))
2433 argTypes.reserve(numArgs);
2434 argLocs.reserve(numArgs);
2444 if (failed(reader.parseVarIntWithFlag(typeIdx, hasLoc)) ||
2445 !(argType = attrTypeReader.resolveType(typeIdx)))
2451 if (failed(
parseType(reader, argType)) ||
2455 argTypes.push_back(argType);
2456 argLocs.push_back(argLoc);
2465 Value BytecodeReader::Impl::parseOperand(EncodingReader &reader) {
2466 std::vector<Value> &values = valueScopes.back().values;
2467 Value *value =
nullptr;
2468 if (failed(
parseEntry(reader, values, value,
"value")))
2473 *value = createForwardRef();
2477 LogicalResult BytecodeReader::Impl::defineValues(EncodingReader &reader,
2479 ValueScope &valueScope = valueScopes.back();
2480 std::vector<Value> &values = valueScope.values;
2482 unsigned &valueID = valueScope.nextValueIDs.back();
2483 unsigned valueIDEnd = valueID + newValues.size();
2484 if (valueIDEnd > values.size()) {
2485 return reader.emitError(
2486 "value index range was outside of the expected range for "
2487 "the parent region, got [",
2488 valueID,
", ", valueIDEnd,
"), but the maximum index was ",
2493 for (
unsigned i = 0, e = newValues.size(); i != e; ++i, ++valueID) {
2494 Value newValue = newValues[i];
2497 if (
Value oldValue = std::exchange(values[valueID], newValue)) {
2498 Operation *forwardRefOp = oldValue.getDefiningOp();
2503 assert(forwardRefOp && forwardRefOp->
getBlock() == &forwardRefOps &&
2504 "value index was already defined?");
2506 oldValue.replaceAllUsesWith(newValue);
2507 forwardRefOp->
moveBefore(&openForwardRefOps, openForwardRefOps.end());
2513 Value BytecodeReader::Impl::createForwardRef() {
2516 if (!openForwardRefOps.empty()) {
2517 Operation *op = &openForwardRefOps.back();
2518 op->
moveBefore(&forwardRefOps, forwardRefOps.end());
2522 return forwardRefOps.back().getResult(0);
2532 llvm::MemoryBufferRef buffer,
const ParserConfig &config,
bool lazyLoading,
2533 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef) {
2537 impl = std::make_unique<Impl>(sourceFileLoc, config, lazyLoading, buffer,
2543 return impl->read(block, lazyOpsCallback);
2547 return impl->getNumOpsToMaterialize();
2551 return impl->isMaterializable(op);
2556 return impl->materialize(op, lazyOpsCallback);
2561 return impl->finalize(shouldMaterialize);
2565 return buffer.getBuffer().starts_with(
"ML\xefR");
2571 static LogicalResult
2574 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef) {
2580 "input buffer is not an MLIR bytecode file");
2584 buffer, bufferOwnerRef);
2585 return reader.
read(block,
nullptr);
2596 *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.
The following classes enable support for parsing and printing resources within MLIR assembly formats.
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.