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"
35 #define DEBUG_TYPE "mlir-bytecode-reader"
47 return "AttrType (2)";
49 return "AttrTypeOffset (3)";
53 return "Resource (5)";
55 return "ResourceOffset (6)";
57 return "DialectVersions (7)";
59 return "Properties (8)";
61 return (
"Unknown (" + Twine(
static_cast<unsigned>(sectionID)) +
")").str();
81 llvm_unreachable(
"unknown section ID");
90 class EncodingReader {
93 : buffer(contents), dataIt(buffer.begin()), fileLoc(fileLoc) {}
94 explicit EncodingReader(StringRef contents,
Location fileLoc)
95 : EncodingReader({
reinterpret_cast<const uint8_t *
>(contents.data()),
100 bool empty()
const {
return dataIt == buffer.end(); }
103 size_t size()
const {
return buffer.end() - dataIt; }
106 LogicalResult alignTo(
unsigned alignment) {
107 if (!llvm::isPowerOf2_32(alignment))
108 return emitError(
"expected alignment to be a power-of-two");
110 auto isUnaligned = [&](
const uint8_t *ptr) {
111 return ((uintptr_t)ptr & (alignment - 1)) != 0;
118 while (isUnaligned(dataIt)) {
120 if (
failed(parseByte(padding)))
123 return emitError(
"expected alignment byte (0xCB), but got: '0x" +
124 llvm::utohexstr(padding) +
"'");
130 if (LLVM_UNLIKELY(isUnaligned(dataIt))) {
131 return emitError(
"expected data iterator aligned to ", alignment,
132 ", but got pointer: '0x" +
133 llvm::utohexstr((uintptr_t)dataIt) +
"'");
140 template <
typename... Args>
147 template <
typename T>
148 LogicalResult parseByte(T &value) {
150 return emitError(
"attempting to parse a byte at the end of the bytecode");
151 value =
static_cast<T
>(*dataIt++);
156 if (length > size()) {
157 return emitError(
"attempting to parse ", length,
" bytes when only ",
160 result = {dataIt, length};
166 LogicalResult parseBytes(
size_t length, uint8_t *result) {
167 if (length > size()) {
168 return emitError(
"attempting to parse ", length,
" bytes when only ",
171 memcpy(result, dataIt, length);
179 uint64_t &alignment) {
181 if (
failed(parseVarInt(alignment)) ||
failed(parseVarInt(dataSize)) ||
182 failed(alignTo(alignment)))
184 return parseBytes(dataSize, data);
194 LogicalResult parseVarInt(uint64_t &result) {
196 if (
failed(parseByte(result)))
201 if (LLVM_LIKELY(result & 1)) {
209 if (LLVM_UNLIKELY(result == 0)) {
210 llvm::support::ulittle64_t resultLE;
211 if (
failed(parseBytes(
sizeof(resultLE),
212 reinterpret_cast<uint8_t *
>(&resultLE))))
217 return parseMultiByteVarInt(result);
223 LogicalResult parseSignedVarInt(uint64_t &result) {
224 if (
failed(parseVarInt(result)))
227 result = (result >> 1) ^ (~(result & 1) + 1);
233 LogicalResult parseVarIntWithFlag(uint64_t &result,
bool &flag) {
234 if (
failed(parseVarInt(result)))
242 LogicalResult skipBytes(
size_t length) {
243 if (length > size()) {
244 return emitError(
"attempting to skip ", length,
" bytes when only ",
253 LogicalResult parseNullTerminatedString(StringRef &result) {
254 const char *startIt = (
const char *)dataIt;
255 const char *nulIt = (
const char *)memchr(startIt, 0, size());
258 "malformed null-terminated string, no null character found");
260 result = StringRef(startIt, nulIt - startIt);
261 dataIt = (
const uint8_t *)nulIt + 1;
266 using ValidateAlignmentFn =
function_ref<LogicalResult(
unsigned alignment)>;
271 ValidateAlignmentFn alignmentValidator,
273 uint8_t sectionIDAndHasAlignment;
275 if (
failed(parseByte(sectionIDAndHasAlignment)) ||
276 failed(parseVarInt(length)))
283 bool hasAlignment = sectionIDAndHasAlignment & 0b10000000;
288 return emitError(
"invalid section ID: ",
unsigned(sectionID));
294 if (
failed(parseVarInt(alignment)))
329 if (
failed(alignmentValidator(alignment)))
330 return emitError(
"failed to align section ID: ",
unsigned(sectionID));
333 if (
failed(alignTo(alignment)))
338 return parseBytes(
static_cast<size_t>(length), sectionData);
341 Location getLoc()
const {
return fileLoc; }
350 LLVM_ATTRIBUTE_NOINLINE LogicalResult parseMultiByteVarInt(uint64_t &result) {
356 uint32_t numBytes = llvm::countr_zero<uint32_t>(result);
357 assert(numBytes > 0 && numBytes <= 7 &&
358 "unexpected number of trailing zeros in varint encoding");
361 llvm::support::ulittle64_t resultLE(result);
363 parseBytes(numBytes,
reinterpret_cast<uint8_t *
>(&resultLE) + 1)))
368 result = resultLE >> (numBytes + 1);
376 const uint8_t *dataIt;
387 template <
typename RangeT,
typename T>
388 static LogicalResult
resolveEntry(EncodingReader &reader, RangeT &entries,
389 uint64_t index, T &entry,
390 StringRef entryStr) {
391 if (index >= entries.size())
392 return reader.emitError(
"invalid ", entryStr,
" index: ", index);
395 if constexpr (std::is_convertible_v<llvm::detail::ValueOfRange<RangeT>, T>)
396 entry = entries[index];
398 entry = &entries[index];
403 template <
typename RangeT,
typename T>
404 static LogicalResult
parseEntry(EncodingReader &reader, RangeT &entries,
405 T &entry, StringRef entryStr) {
407 if (
failed(reader.parseVarInt(entryIdx)))
409 return resolveEntry(reader, entries, entryIdx, entry, entryStr);
419 class StringSectionReader {
426 LogicalResult parseString(EncodingReader &reader, StringRef &result)
const {
427 return parseEntry(reader, strings, result,
"string");
433 LogicalResult parseStringWithFlag(EncodingReader &reader, StringRef &result,
436 if (
failed(reader.parseVarIntWithFlag(entryIdx, flag)))
438 return parseStringAtIndex(reader, entryIdx, result);
443 LogicalResult parseStringAtIndex(EncodingReader &reader, uint64_t index,
444 StringRef &result)
const {
445 return resolveEntry(reader, strings, index, result,
"string");
454 LogicalResult StringSectionReader::initialize(
Location fileLoc,
456 EncodingReader stringReader(sectionData, fileLoc);
460 if (
failed(stringReader.parseVarInt(numStrings)))
462 strings.resize(numStrings);
466 size_t stringDataEndOffset = sectionData.size();
467 for (StringRef &
string : llvm::reverse(strings)) {
469 if (
failed(stringReader.parseVarInt(stringSize)))
471 if (stringDataEndOffset < stringSize) {
472 return stringReader.emitError(
473 "string size exceeds the available data size");
477 size_t stringOffset = stringDataEndOffset - stringSize;
479 reinterpret_cast<const char *
>(sectionData.data() + stringOffset),
481 stringDataEndOffset = stringOffset;
486 if ((sectionData.size() - stringReader.size()) != stringDataEndOffset) {
487 return stringReader.emitError(
"unexpected trailing data between the "
488 "offsets for strings and their data");
501 struct BytecodeDialect {
506 LogicalResult load(
const DialectReader &reader,
MLIRContext *ctx);
510 Dialect *getLoadedDialect()
const {
512 "expected `load` to be invoked before `getLoadedDialect`");
519 std::optional<Dialect *> dialect;
533 std::unique_ptr<DialectVersion> loadedVersion;
537 struct BytecodeOperationName {
538 BytecodeOperationName(BytecodeDialect *dialect, StringRef name,
539 std::optional<bool> wasRegistered)
540 : dialect(dialect), name(name), wasRegistered(wasRegistered) {}
544 std::optional<OperationName> opName;
547 BytecodeDialect *dialect;
554 std::optional<bool> wasRegistered;
560 EncodingReader &reader,
562 function_ref<LogicalResult(BytecodeDialect *)> entryCallback) {
564 std::unique_ptr<BytecodeDialect> *dialect;
568 if (
failed(reader.parseVarInt(numEntries)))
571 for (uint64_t i = 0; i < numEntries; ++i)
572 if (
failed(entryCallback(dialect->get())))
583 class ResourceSectionReader {
591 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef);
594 LogicalResult parseResourceHandle(EncodingReader &reader,
596 return parseEntry(reader, dialectResources, result,
"resource handle");
602 llvm::StringMap<std::string> dialectResourceHandleRenamingMap;
608 EncodingReader &reader, StringSectionReader &stringReader,
609 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef)
610 : key(key),
kind(
kind), reader(reader), stringReader(stringReader),
611 bufferOwnerRef(bufferOwnerRef) {}
612 ~ParsedResourceEntry()
override =
default;
614 StringRef getKey() const final {
return key; }
620 FailureOr<bool> parseAsBool() const final {
622 return emitError() <<
"expected a bool resource entry, but found a "
626 if (
failed(reader.parseByte(value)))
630 FailureOr<std::string> parseAsString() const final {
632 return emitError() <<
"expected a string resource entry, but found a "
636 if (
failed(stringReader.parseString(reader,
string)))
641 FailureOr<AsmResourceBlob>
642 parseAsBlob(BlobAllocatorFn allocator)
const final {
644 return emitError() <<
"expected a blob resource entry, but found a "
649 if (
failed(reader.parseBlobAndAlignment(data, alignment)))
654 if (bufferOwnerRef) {
655 ArrayRef<char> charData(
reinterpret_cast<const char *
>(data.data()),
663 [bufferOwnerRef = bufferOwnerRef](
void *,
size_t,
size_t) {});
669 assert(llvm::isAddrAligned(llvm::Align(alignment), blob.
getData().data()) &&
671 "blob allocator did not return a properly aligned address");
679 EncodingReader &reader;
680 StringSectionReader &stringReader;
681 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef;
685 template <
typename T>
688 EncodingReader &offsetReader, EncodingReader &resourceReader,
689 StringSectionReader &stringReader, T *handler,
690 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef,
692 function_ref<LogicalResult(StringRef)> processKeyFn = {}) {
693 uint64_t numResources;
694 if (
failed(offsetReader.parseVarInt(numResources)))
697 for (uint64_t i = 0; i < numResources; ++i) {
700 uint64_t resourceOffset;
702 if (
failed(stringReader.parseString(offsetReader, key)) ||
703 failed(offsetReader.parseVarInt(resourceOffset)) ||
705 failed(resourceReader.parseBytes(resourceOffset, data)))
709 if ((processKeyFn &&
failed(processKeyFn(key))))
714 if (allowEmpty && data.empty())
722 EncodingReader entryReader(data, fileLoc);
724 ParsedResourceEntry entry(key,
kind, entryReader, stringReader,
726 if (
failed(handler->parseResource(entry)))
728 if (!entryReader.empty()) {
729 return entryReader.emitError(
730 "unexpected trailing bytes in resource entry '", key,
"'");
736 LogicalResult ResourceSectionReader::initialize(
741 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef) {
742 EncodingReader resourceReader(sectionData, fileLoc);
743 EncodingReader offsetReader(offsetSectionData, fileLoc);
746 uint64_t numExternalResourceGroups;
747 if (
failed(offsetReader.parseVarInt(numExternalResourceGroups)))
752 auto parseGroup = [&](
auto *handler,
bool allowEmpty =
false,
754 auto resolveKey = [&](StringRef key) -> StringRef {
755 auto it = dialectResourceHandleRenamingMap.find(key);
756 if (it == dialectResourceHandleRenamingMap.end())
762 stringReader, handler, bufferOwnerRef, resolveKey,
767 for (uint64_t i = 0; i < numExternalResourceGroups; ++i) {
769 if (
failed(stringReader.parseString(offsetReader, key)))
776 emitWarning(fileLoc) <<
"ignoring unknown external resources for '" << key
780 if (
failed(parseGroup(handler)))
786 while (!offsetReader.empty()) {
787 std::unique_ptr<BytecodeDialect> *dialect;
789 failed((*dialect)->load(dialectReader, ctx)))
791 Dialect *loadedDialect = (*dialect)->getLoadedDialect();
792 if (!loadedDialect) {
793 return resourceReader.emitError()
794 <<
"dialect '" << (*dialect)->name <<
"' is unknown";
796 const auto *handler = dyn_cast<OpAsmDialectInterface>(loadedDialect);
798 return resourceReader.emitError()
799 <<
"unexpected resources for dialect '" << (*dialect)->name <<
"'";
803 auto processResourceKeyFn = [&](StringRef key) -> LogicalResult {
804 FailureOr<AsmDialectResourceHandle> handle =
805 handler->declareResource(key);
807 return resourceReader.emitError()
808 <<
"unknown 'resource' key '" << key <<
"' for dialect '"
809 << (*dialect)->name <<
"'";
811 dialectResourceHandleRenamingMap[key] = handler->getResourceKey(*handle);
812 dialectResources.push_back(*handle);
818 if (
failed(parseGroup(handler,
true, processResourceKeyFn)))
833 class AttrTypeReader {
835 template <
typename T>
840 BytecodeDialect *dialect =
nullptr;
843 bool hasCustomEncoding =
false;
847 using AttrEntry = Entry<Attribute>;
848 using TypeEntry = Entry<Type>;
851 AttrTypeReader(
const StringSectionReader &stringReader,
852 const ResourceSectionReader &resourceReader,
853 const llvm::StringMap<BytecodeDialect *> &dialectsMap,
854 uint64_t &bytecodeVersion,
Location fileLoc,
856 : stringReader(stringReader), resourceReader(resourceReader),
857 dialectsMap(dialectsMap), fileLoc(fileLoc),
858 bytecodeVersion(bytecodeVersion), parserConfig(
config) {}
868 Attribute resolveAttribute(
size_t index) {
871 Type resolveType(
size_t index) {
return resolveEntry(types, index,
"Type"); }
876 if (
failed(reader.parseVarInt(attrIdx)))
878 result = resolveAttribute(attrIdx);
879 return success(!!result);
881 LogicalResult parseOptionalAttribute(EncodingReader &reader,
885 if (
failed(reader.parseVarIntWithFlag(attrIdx, flag)))
889 result = resolveAttribute(attrIdx);
890 return success(!!result);
893 LogicalResult
parseType(EncodingReader &reader,
Type &result) {
895 if (
failed(reader.parseVarInt(typeIdx)))
897 result = resolveType(typeIdx);
898 return success(!!result);
901 template <
typename T>
906 if ((result = dyn_cast<T>(baseResult)))
908 return reader.emitError(
"expected attribute of type: ",
909 llvm::getTypeName<T>(),
", but got: ", baseResult);
914 template <
typename T>
916 StringRef entryType);
920 template <
typename T>
921 LogicalResult parseAsmEntry(T &result, EncodingReader &reader,
922 StringRef entryType);
926 template <
typename T>
927 LogicalResult parseCustomEntry(Entry<T> &entry, EncodingReader &reader,
928 StringRef entryType);
932 const StringSectionReader &stringReader;
936 const ResourceSectionReader &resourceReader;
940 const llvm::StringMap<BytecodeDialect *> &dialectsMap;
950 uint64_t &bytecodeVersion;
958 DialectReader(AttrTypeReader &attrTypeReader,
959 const StringSectionReader &stringReader,
960 const ResourceSectionReader &resourceReader,
961 const llvm::StringMap<BytecodeDialect *> &dialectsMap,
962 EncodingReader &reader, uint64_t &bytecodeVersion)
963 : attrTypeReader(attrTypeReader), stringReader(stringReader),
964 resourceReader(resourceReader), dialectsMap(dialectsMap),
965 reader(reader), bytecodeVersion(bytecodeVersion) {}
968 return reader.emitError(msg);
971 FailureOr<const DialectVersion *>
972 getDialectVersion(StringRef dialectName)
const override {
974 auto dialectEntry = dialectsMap.find(dialectName);
975 if (dialectEntry == dialectsMap.end())
981 dialectEntry->getValue()->loadedVersion ==
nullptr)
983 return dialectEntry->getValue()->loadedVersion.get();
988 uint64_t getBytecodeVersion()
const override {
return bytecodeVersion; }
990 DialectReader withEncodingReader(EncodingReader &encReader)
const {
991 return DialectReader(attrTypeReader, stringReader, resourceReader,
992 dialectsMap, encReader, bytecodeVersion);
995 Location getLoc()
const {
return reader.getLoc(); }
1001 LogicalResult readAttribute(
Attribute &result)
override {
1002 return attrTypeReader.parseAttribute(reader, result);
1004 LogicalResult readOptionalAttribute(
Attribute &result)
override {
1005 return attrTypeReader.parseOptionalAttribute(reader, result);
1007 LogicalResult readType(
Type &result)
override {
1008 return attrTypeReader.parseType(reader, result);
1013 if (
failed(resourceReader.parseResourceHandle(reader, handle)))
1022 LogicalResult readVarInt(uint64_t &result)
override {
1023 return reader.parseVarInt(result);
1026 LogicalResult readSignedVarInt(int64_t &result)
override {
1027 uint64_t unsignedResult;
1028 if (
failed(reader.parseSignedVarInt(unsignedResult)))
1030 result =
static_cast<int64_t
>(unsignedResult);
1034 FailureOr<APInt> readAPIntWithKnownWidth(
unsigned bitWidth)
override {
1036 if (bitWidth <= 8) {
1038 if (
failed(reader.parseByte(value)))
1040 return APInt(bitWidth, value);
1044 if (bitWidth <= 64) {
1046 if (
failed(reader.parseSignedVarInt(value)))
1048 return APInt(bitWidth, value);
1053 uint64_t numActiveWords;
1054 if (
failed(reader.parseVarInt(numActiveWords)))
1057 for (uint64_t i = 0; i < numActiveWords; ++i)
1058 if (
failed(reader.parseSignedVarInt(words[i])))
1060 return APInt(bitWidth, words);
1064 readAPFloatWithKnownSemantics(
const llvm::fltSemantics &semantics)
override {
1065 FailureOr<APInt> intVal =
1066 readAPIntWithKnownWidth(APFloat::getSizeInBits(semantics));
1069 return APFloat(semantics, *intVal);
1072 LogicalResult readString(StringRef &result)
override {
1073 return stringReader.parseString(reader, result);
1079 if (
failed(reader.parseVarInt(dataSize)) ||
1080 failed(reader.parseBytes(dataSize, data)))
1082 result =
llvm::ArrayRef(
reinterpret_cast<const char *
>(data.data()),
1087 LogicalResult readBool(
bool &result)
override {
1088 return reader.parseByte(result);
1092 AttrTypeReader &attrTypeReader;
1093 const StringSectionReader &stringReader;
1094 const ResourceSectionReader &resourceReader;
1095 const llvm::StringMap<BytecodeDialect *> &dialectsMap;
1096 EncodingReader &reader;
1097 uint64_t &bytecodeVersion;
1101 class PropertiesSectionReader {
1105 if (sectionData.empty())
1107 EncodingReader propReader(sectionData, fileLoc);
1109 if (
failed(propReader.parseVarInt(count)))
1112 if (
failed(propReader.parseBytes(propReader.size(), propertiesBuffers)))
1115 EncodingReader offsetsReader(propertiesBuffers, fileLoc);
1116 offsetTable.reserve(count);
1117 for (
auto idx : llvm::seq<int64_t>(0, count)) {
1119 offsetTable.push_back(propertiesBuffers.size() - offsetsReader.size());
1122 if (
failed(offsetsReader.parseVarInt(dataSize)) ||
1123 failed(offsetsReader.parseBytes(dataSize, rawProperties)))
1126 if (!offsetsReader.empty())
1127 return offsetsReader.emitError()
1128 <<
"Broken properties section: didn't exhaust the offsets table";
1132 LogicalResult read(
Location fileLoc, DialectReader &dialectReader,
1134 uint64_t propertiesIdx;
1135 if (
failed(dialectReader.readVarInt(propertiesIdx)))
1137 if (propertiesIdx >= offsetTable.size())
1138 return dialectReader.emitError(
"Properties idx out-of-bound for ")
1140 size_t propertiesOffset = offsetTable[propertiesIdx];
1141 if (propertiesIdx >= propertiesBuffers.size())
1142 return dialectReader.emitError(
"Properties offset out-of-bound for ")
1150 EncodingReader reader(propertiesBuffers.drop_front(propertiesOffset),
1154 dialectReader.withEncodingReader(reader).readBlob(rawProperties)))
1158 EncodingReader reader(
1159 StringRef(rawProperties.begin(), rawProperties.size()), fileLoc);
1160 DialectReader propReader = dialectReader.withEncodingReader(reader);
1162 auto *iface = opName->
getInterface<BytecodeOpInterface>();
1164 return iface->readProperties(propReader, opState);
1166 return propReader.emitError(
1167 "has properties but missing BytecodeOpInterface for ")
1182 LogicalResult AttrTypeReader::initialize(
1185 EncodingReader offsetReader(offsetSectionData, fileLoc);
1188 uint64_t numAttributes, numTypes;
1189 if (
failed(offsetReader.parseVarInt(numAttributes)) ||
1190 failed(offsetReader.parseVarInt(numTypes)))
1192 attributes.resize(numAttributes);
1193 types.resize(numTypes);
1197 uint64_t currentOffset = 0;
1198 auto parseEntries = [&](
auto &&range) {
1199 size_t currentIndex = 0, endIndex = range.size();
1202 auto parseEntryFn = [&](BytecodeDialect *dialect) -> LogicalResult {
1203 auto &entry = range[currentIndex++];
1206 if (
failed(offsetReader.parseVarIntWithFlag(entrySize,
1207 entry.hasCustomEncoding)))
1211 if (currentOffset + entrySize > sectionData.size()) {
1212 return offsetReader.emitError(
1213 "Attribute or Type entry offset points past the end of section");
1216 entry.data = sectionData.slice(currentOffset, entrySize);
1217 entry.dialect = dialect;
1218 currentOffset += entrySize;
1221 while (currentIndex != endIndex)
1228 if (
failed(parseEntries(attributes)) ||
failed(parseEntries(types)))
1232 if (!offsetReader.empty()) {
1233 return offsetReader.emitError(
1234 "unexpected trailing data in the Attribute/Type offset section");
1240 template <
typename T>
1242 StringRef entryType) {
1243 if (index >= entries.size()) {
1244 emitError(fileLoc) <<
"invalid " << entryType <<
" index: " << index;
1249 Entry<T> &entry = entries[index];
1254 EncodingReader reader(entry.data, fileLoc);
1257 if (entry.hasCustomEncoding) {
1258 if (
failed(parseCustomEntry(entry, reader, entryType)))
1260 }
else if (
failed(parseAsmEntry(entry.entry, reader, entryType))) {
1264 if (!reader.empty()) {
1265 reader.emitError(
"unexpected trailing bytes after " + entryType +
" entry");
1271 template <
typename T>
1272 LogicalResult AttrTypeReader::parseAsmEntry(T &result, EncodingReader &reader,
1273 StringRef entryType) {
1275 if (
failed(reader.parseNullTerminatedString(asmStr)))
1281 if constexpr (std::is_same_v<T, Type>)
1291 if (numRead != asmStr.size()) {
1292 return reader.emitError(
"trailing characters found after ", entryType,
1293 " assembly format: ", asmStr.drop_front(numRead));
1298 template <
typename T>
1299 LogicalResult AttrTypeReader::parseCustomEntry(Entry<T> &entry,
1300 EncodingReader &reader,
1301 StringRef entryType) {
1302 DialectReader dialectReader(*
this, stringReader, resourceReader, dialectsMap,
1303 reader, bytecodeVersion);
1307 if constexpr (std::is_same_v<T, Type>) {
1309 for (
const auto &callback :
1310 parserConfig.getBytecodeReaderConfig().getTypeCallbacks()) {
1312 callback->read(dialectReader, entry.dialect->name, entry.entry)))
1320 reader = EncodingReader(entry.data, reader.getLoc());
1324 for (
const auto &callback :
1325 parserConfig.getBytecodeReaderConfig().getAttributeCallbacks()) {
1327 callback->read(dialectReader, entry.dialect->name, entry.entry)))
1335 reader = EncodingReader(entry.data, reader.getLoc());
1340 if (!entry.dialect->interface) {
1341 return reader.emitError(
"dialect '", entry.dialect->name,
1342 "' does not implement the bytecode interface");
1345 if constexpr (std::is_same_v<T, Type>)
1346 entry.entry = entry.dialect->interface->readType(dialectReader);
1348 entry.entry = entry.dialect->interface->readAttribute(dialectReader);
1350 return success(!!entry.entry);
1359 struct RegionReadState;
1360 using LazyLoadableOpsInfo =
1361 std::list<std::pair<Operation *, RegionReadState>>;
1362 using LazyLoadableOpsMap =
1367 llvm::MemoryBufferRef buffer,
1368 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef)
1369 :
config(
config), fileLoc(fileLoc), lazyLoading(lazyLoading),
1370 attrTypeReader(stringReader, resourceReader, dialectsMap, version,
1375 "builtin.unrealized_conversion_cast",
ValueRange(),
1377 buffer(buffer), bufferOwnerRef(bufferOwnerRef) {}
1393 this->lazyOpsCallback = lazyOpsCallback;
1394 auto resetlazyOpsCallback =
1395 llvm::make_scope_exit([&] { this->lazyOpsCallback =
nullptr; });
1396 auto it = lazyLoadableOpsMap.find(op);
1397 assert(it != lazyLoadableOpsMap.end() &&
1398 "materialize called on non-materializable op");
1404 while (!lazyLoadableOpsMap.empty()) {
1416 while (!lazyLoadableOps.empty()) {
1417 Operation *op = lazyLoadableOps.begin()->first;
1418 if (shouldMaterialize(op)) {
1425 lazyLoadableOps.pop_front();
1426 lazyLoadableOpsMap.erase(op);
1432 LogicalResult
materialize(LazyLoadableOpsMap::iterator it) {
1433 assert(it != lazyLoadableOpsMap.end() &&
1434 "materialize called on non-materializable op");
1435 valueScopes.emplace_back();
1436 std::vector<RegionReadState> regionStack;
1437 regionStack.push_back(std::move(it->getSecond()->second));
1438 lazyLoadableOps.erase(it->getSecond());
1439 lazyLoadableOpsMap.erase(it);
1441 while (!regionStack.empty())
1447 LogicalResult checkSectionAlignment(
1458 const bool isGloballyAligned =
1459 ((uintptr_t)buffer.getBufferStart() & (alignment - 1)) == 0;
1461 if (!isGloballyAligned)
1462 return emitError(
"expected section alignment ")
1463 << alignment <<
" but bytecode buffer 0x"
1464 << Twine::utohexstr((uint64_t)buffer.getBufferStart())
1465 <<
" is not aligned";
1474 LogicalResult parseVersion(EncodingReader &reader);
1484 FailureOr<OperationName> parseOpName(EncodingReader &reader,
1485 std::optional<bool> &wasRegistered);
1491 template <
typename T>
1492 LogicalResult
parseAttribute(EncodingReader &reader, T &result) {
1493 return attrTypeReader.parseAttribute(reader, result);
1495 LogicalResult
parseType(EncodingReader &reader,
Type &result) {
1496 return attrTypeReader.parseType(reader, result);
1503 parseResourceSection(EncodingReader &reader,
1512 struct RegionReadState {
1513 RegionReadState(
Operation *op, EncodingReader *reader,
1514 bool isIsolatedFromAbove)
1515 : RegionReadState(op->getRegions(), reader, isIsolatedFromAbove) {}
1517 bool isIsolatedFromAbove)
1518 : curRegion(regions.begin()), endRegion(regions.end()), reader(reader),
1519 isIsolatedFromAbove(isIsolatedFromAbove) {}
1527 EncodingReader *reader;
1528 std::unique_ptr<EncodingReader> owningReader;
1531 unsigned numValues = 0;
1539 uint64_t numOpsRemaining = 0;
1542 bool isIsolatedFromAbove =
false;
1546 LogicalResult parseRegions(std::vector<RegionReadState> ®ionStack,
1547 RegionReadState &readState);
1548 FailureOr<Operation *> parseOpWithoutRegions(EncodingReader &reader,
1549 RegionReadState &readState,
1550 bool &isIsolatedFromAbove);
1552 LogicalResult parseRegion(RegionReadState &readState);
1553 LogicalResult parseBlockHeader(EncodingReader &reader,
1554 RegionReadState &readState);
1555 LogicalResult parseBlockArguments(EncodingReader &reader,
Block *block);
1562 Value parseOperand(EncodingReader &reader);
1565 LogicalResult defineValues(EncodingReader &reader,
ValueRange values);
1568 Value createForwardRef();
1576 struct UseListOrderStorage {
1577 UseListOrderStorage(
bool isIndexPairEncoding,
1579 : indices(std::move(indices)),
1580 isIndexPairEncoding(isIndexPairEncoding) {};
1587 bool isIndexPairEncoding;
1596 FailureOr<UseListMapT> parseUseListOrderForRange(EncodingReader &reader,
1597 uint64_t rangeSize);
1600 LogicalResult sortUseListOrder(
Value value);
1604 LogicalResult processUseLists(
Operation *topLevelOp);
1614 void push(RegionReadState &readState) {
1615 nextValueIDs.push_back(values.size());
1616 values.resize(values.size() + readState.numValues);
1621 void pop(RegionReadState &readState) {
1622 values.resize(values.size() - readState.numValues);
1623 nextValueIDs.pop_back();
1627 std::vector<Value> values;
1646 LazyLoadableOpsInfo lazyLoadableOps;
1647 LazyLoadableOpsMap lazyLoadableOpsMap;
1651 AttrTypeReader attrTypeReader;
1654 uint64_t version = 0;
1661 llvm::StringMap<BytecodeDialect *> dialectsMap;
1665 ResourceSectionReader resourceReader;
1672 StringSectionReader stringReader;
1675 PropertiesSectionReader propertiesReader;
1678 std::vector<ValueScope> valueScopes;
1685 Block forwardRefOps;
1689 Block openForwardRefOps;
1695 llvm::MemoryBufferRef buffer;
1699 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef;
1704 EncodingReader reader(buffer.getBuffer(), fileLoc);
1705 this->lazyOpsCallback = lazyOpsCallback;
1706 auto resetlazyOpsCallback =
1707 llvm::make_scope_exit([&] { this->lazyOpsCallback =
nullptr; });
1710 if (
failed(reader.skipBytes(StringRef(
"ML\xefR").size())))
1713 if (
failed(parseVersion(reader)) ||
1714 failed(reader.parseNullTerminatedString(producer)))
1720 diag.attachNote() <<
"in bytecode version " << version
1721 <<
" produced by: " << producer;
1725 const auto checkSectionAlignment = [&](
unsigned alignment) {
1726 return this->checkSectionAlignment(
1727 alignment, [&](
const auto &msg) {
return reader.emitError(msg); });
1731 std::optional<ArrayRef<uint8_t>>
1733 while (!reader.empty()) {
1738 reader.parseSection(sectionID, checkSectionAlignment, sectionData)))
1742 if (sectionDatas[sectionID]) {
1743 return reader.emitError(
"duplicate top-level section: ",
1746 sectionDatas[sectionID] = sectionData;
1752 return reader.emitError(
"missing data for top-level section: ",
1758 if (
failed(stringReader.initialize(
1764 failed(propertiesReader.initialize(
1773 if (
failed(parseResourceSection(
1779 if (
failed(attrTypeReader.initialize(
1788 LogicalResult BytecodeReader::Impl::parseVersion(EncodingReader &reader) {
1789 if (
failed(reader.parseVarInt(version)))
1795 if (version < minSupportedVersion) {
1796 return reader.emitError(
"bytecode version ", version,
1797 " is older than the current version of ",
1798 currentVersion,
", and upgrade is not supported");
1800 if (version > currentVersion) {
1801 return reader.emitError(
"bytecode version ", version,
1802 " is newer than the current version ",
1807 lazyLoading =
false;
1815 LogicalResult BytecodeDialect::load(
const DialectReader &reader,
1821 return reader.emitError(
"dialect '")
1823 <<
"' is unknown. If this is intended, please call "
1824 "allowUnregisteredDialects() on the MLIRContext, or use "
1825 "-allow-unregistered-dialect with the MLIR tool used.";
1827 dialect = loadedDialect;
1833 if (!versionBuffer.empty()) {
1835 return reader.emitError(
"dialect '")
1837 <<
"' does not implement the bytecode interface, "
1838 "but found a version entry";
1839 EncodingReader encReader(versionBuffer, reader.getLoc());
1840 DialectReader versionReader = reader.withEncodingReader(encReader);
1841 loadedVersion = interface->readVersion(versionReader);
1850 EncodingReader sectionReader(sectionData, fileLoc);
1853 uint64_t numDialects;
1854 if (
failed(sectionReader.parseVarInt(numDialects)))
1856 dialects.resize(numDialects);
1858 const auto checkSectionAlignment = [&](
unsigned alignment) {
1859 return this->checkSectionAlignment(alignment, [&](
const auto &msg) {
1860 return sectionReader.emitError(msg);
1865 for (uint64_t i = 0; i < numDialects; ++i) {
1866 dialects[i] = std::make_unique<BytecodeDialect>();
1870 if (
failed(stringReader.parseString(sectionReader, dialects[i]->name)))
1876 uint64_t dialectNameIdx;
1877 bool versionAvailable;
1878 if (
failed(sectionReader.parseVarIntWithFlag(dialectNameIdx,
1881 if (
failed(stringReader.parseStringAtIndex(sectionReader, dialectNameIdx,
1882 dialects[i]->name)))
1884 if (versionAvailable) {
1886 if (
failed(sectionReader.parseSection(sectionID, checkSectionAlignment,
1887 dialects[i]->versionBuffer)))
1890 emitError(fileLoc,
"expected dialect version section");
1894 dialectsMap[dialects[i]->name] = dialects[i].get();
1898 auto parseOpName = [&](BytecodeDialect *dialect) {
1900 std::optional<bool> wasRegistered;
1904 if (
failed(stringReader.parseString(sectionReader, opName)))
1907 bool wasRegisteredFlag;
1908 if (
failed(stringReader.parseStringWithFlag(sectionReader, opName,
1909 wasRegisteredFlag)))
1911 wasRegistered = wasRegisteredFlag;
1913 opNames.emplace_back(dialect, opName, wasRegistered);
1920 if (
failed(sectionReader.parseVarInt(numOps)))
1922 opNames.reserve(numOps);
1924 while (!sectionReader.empty())
1930 FailureOr<OperationName>
1931 BytecodeReader::Impl::parseOpName(EncodingReader &reader,
1932 std::optional<bool> &wasRegistered) {
1933 BytecodeOperationName *opName =
nullptr;
1936 wasRegistered = opName->wasRegistered;
1939 if (!opName->opName) {
1944 if (opName->name.empty()) {
1945 opName->opName.emplace(opName->dialect->name,
getContext());
1948 DialectReader dialectReader(attrTypeReader, stringReader, resourceReader,
1949 dialectsMap, reader, version);
1952 opName->opName.emplace((opName->dialect->name +
"." + opName->name).str(),
1956 return *opName->opName;
1963 LogicalResult BytecodeReader::Impl::parseResourceSection(
1967 if (resourceData.has_value() != resourceOffsetData.has_value()) {
1968 if (resourceOffsetData)
1969 return emitError(fileLoc,
"unexpected resource offset section when "
1970 "resource section is not present");
1973 "expected resource offset section when resource section is present");
1981 DialectReader dialectReader(attrTypeReader, stringReader, resourceReader,
1982 dialectsMap, reader, version);
1983 return resourceReader.initialize(fileLoc,
config, dialects, stringReader,
1984 *resourceData, *resourceOffsetData,
1985 dialectReader, bufferOwnerRef);
1992 FailureOr<BytecodeReader::Impl::UseListMapT>
1993 BytecodeReader::Impl::parseUseListOrderForRange(EncodingReader &reader,
1994 uint64_t numResults) {
1996 uint64_t numValuesToRead = 1;
1997 if (numResults > 1 &&
failed(reader.parseVarInt(numValuesToRead)))
2000 for (
size_t valueIdx = 0; valueIdx < numValuesToRead; valueIdx++) {
2001 uint64_t resultIdx = 0;
2002 if (numResults > 1 &&
failed(reader.parseVarInt(resultIdx)))
2006 bool indexPairEncoding;
2007 if (
failed(reader.parseVarIntWithFlag(numValues, indexPairEncoding)))
2011 for (
size_t idx = 0; idx < numValues; idx++) {
2013 if (
failed(reader.parseVarInt(index)))
2015 useListOrders.push_back(index);
2019 map.try_emplace(resultIdx, UseListOrderStorage(indexPairEncoding,
2020 std::move(useListOrders)));
2031 LogicalResult BytecodeReader::Impl::sortUseListOrder(
Value value) {
2036 bool hasIncomingOrder =
2041 bool alreadySorted =
true;
2048 item.value(), operationIDs.at(item.value().getOwner()));
2049 alreadySorted &= prevID > currentID;
2050 currentOrder.push_back({item.index(), currentID});
2056 if (alreadySorted && !hasIncomingOrder)
2063 currentOrder.begin(), currentOrder.end(),
2064 [](
auto elem1,
auto elem2) { return elem1.second > elem2.second; });
2066 if (!hasIncomingOrder) {
2076 UseListOrderStorage customOrder =
2084 if (customOrder.isIndexPairEncoding) {
2086 if (shuffle.size() & 1)
2091 std::iota(newShuffle.begin(), newShuffle.end(), idx);
2092 for (idx = 0; idx < shuffle.size(); idx += 2)
2093 newShuffle[shuffle[idx]] = shuffle[idx + 1];
2095 shuffle = std::move(newShuffle);
2102 uint64_t accumulator = 0;
2103 for (
const auto &elem : shuffle) {
2104 if (!set.insert(elem).second)
2106 accumulator += elem;
2108 if (numUses != shuffle.size() ||
2109 accumulator != (((numUses - 1) * numUses) >> 1))
2115 currentOrder, [&](
auto item) {
return shuffle[item.first]; }));
2120 LogicalResult BytecodeReader::Impl::processUseLists(
Operation *topLevelOp) {
2124 unsigned operationID = 0;
2126 [&](
Operation *op) { operationIDs.try_emplace(op, operationID++); });
2128 auto blockWalk = topLevelOp->
walk([
this](
Block *block) {
2130 if (
failed(sortUseListOrder(arg)))
2137 if (
failed(sortUseListOrder(result)))
2142 return failure(blockWalk.wasInterrupted() || resultWalk.wasInterrupted());
2152 EncodingReader reader(sectionData, fileLoc);
2155 std::vector<RegionReadState> regionStack;
2159 regionStack.emplace_back(*moduleOp, &reader,
true);
2160 regionStack.back().curBlocks.push_back(moduleOp->getBody());
2161 regionStack.back().curBlock = regionStack.back().curRegion->begin();
2162 if (
failed(parseBlockHeader(reader, regionStack.back())))
2164 valueScopes.emplace_back();
2165 valueScopes.back().push(regionStack.back());
2168 while (!regionStack.empty())
2171 if (!forwardRefOps.empty()) {
2172 return reader.emitError(
2173 "not all forward unresolved forward operand references");
2177 if (
failed(processUseLists(*moduleOp)))
2178 return reader.emitError(
2179 "parsed use-list orders were invalid and could not be applied");
2182 for (
const std::unique_ptr<BytecodeDialect> &byteCodeDialect : dialects) {
2185 if (!byteCodeDialect->loadedVersion)
2187 if (byteCodeDialect->interface &&
2188 failed(byteCodeDialect->interface->upgradeFromVersion(
2189 *moduleOp, *byteCodeDialect->loadedVersion)))
2198 auto &parsedOps = moduleOp->getBody()->getOperations();
2200 destOps.splice(destOps.end(), parsedOps, parsedOps.begin(), parsedOps.end());
2206 RegionReadState &readState) {
2207 const auto checkSectionAlignment = [&](
unsigned alignment) {
2208 return this->checkSectionAlignment(
2209 alignment, [&](
const auto &msg) {
return emitError(fileLoc, msg); });
2215 for (; readState.curRegion != readState.endRegion; ++readState.curRegion) {
2221 if (
failed(parseRegion(readState)))
2225 if (readState.curRegion->empty())
2230 EncodingReader &reader = *readState.reader;
2232 while (readState.numOpsRemaining--) {
2235 bool isIsolatedFromAbove =
false;
2236 FailureOr<Operation *> op =
2237 parseOpWithoutRegions(reader, readState, isIsolatedFromAbove);
2245 if ((*op)->getNumRegions()) {
2246 RegionReadState childState(*op, &reader, isIsolatedFromAbove);
2252 if (
failed(reader.parseSection(sectionID, checkSectionAlignment,
2256 return emitError(fileLoc,
"expected IR section for region");
2257 childState.owningReader =
2258 std::make_unique<EncodingReader>(sectionData, fileLoc);
2259 childState.reader = childState.owningReader.get();
2263 if (lazyLoading && (!lazyOpsCallback || !lazyOpsCallback(*op))) {
2264 lazyLoadableOps.emplace_back(*op, std::move(childState));
2265 lazyLoadableOpsMap.try_emplace(*op,
2266 std::prev(lazyLoadableOps.end()));
2270 regionStack.push_back(std::move(childState));
2273 if (isIsolatedFromAbove)
2274 valueScopes.emplace_back();
2280 if (++readState.curBlock == readState.curRegion->end())
2282 if (
failed(parseBlockHeader(reader, readState)))
2287 readState.curBlock = {};
2288 valueScopes.back().pop(readState);
2293 if (readState.isIsolatedFromAbove) {
2294 assert(!valueScopes.empty() &&
"Expect a valueScope after reading region");
2295 valueScopes.pop_back();
2297 assert(!regionStack.empty() &&
"Expect a regionStack after reading region");
2298 regionStack.pop_back();
2302 FailureOr<Operation *>
2303 BytecodeReader::Impl::parseOpWithoutRegions(EncodingReader &reader,
2304 RegionReadState &readState,
2305 bool &isIsolatedFromAbove) {
2307 std::optional<bool> wasRegistered;
2308 FailureOr<OperationName> opName = parseOpName(reader, wasRegistered);
2315 if (
failed(reader.parseByte(opMask)))
2329 DictionaryAttr dictAttr;
2340 "Unexpected missing `wasRegistered` opname flag at "
2341 "bytecode version ")
2342 << version <<
" with properties.";
2346 if (wasRegistered) {
2347 DialectReader dialectReader(attrTypeReader, stringReader, resourceReader,
2348 dialectsMap, reader, version);
2350 propertiesReader.read(fileLoc, dialectReader, &*opName, opState)))
2362 uint64_t numResults;
2363 if (
failed(reader.parseVarInt(numResults)))
2365 opState.
types.resize(numResults);
2366 for (
int i = 0, e = numResults; i < e; ++i)
2373 uint64_t numOperands;
2374 if (
failed(reader.parseVarInt(numOperands)))
2376 opState.
operands.resize(numOperands);
2377 for (
int i = 0, e = numOperands; i < e; ++i)
2378 if (!(opState.
operands[i] = parseOperand(reader)))
2385 if (
failed(reader.parseVarInt(numSuccs)))
2388 for (
int i = 0, e = numSuccs; i < e; ++i) {
2397 std::optional<UseListMapT> resultIdxToUseListMap = std::nullopt;
2400 size_t numResults = opState.
types.size();
2401 auto parseResult = parseUseListOrderForRange(reader, numResults);
2404 resultIdxToUseListMap = std::move(*parseResult);
2409 uint64_t numRegions;
2410 if (
failed(reader.parseVarIntWithFlag(numRegions, isIsolatedFromAbove)))
2413 opState.
regions.reserve(numRegions);
2414 for (
int i = 0, e = numRegions; i < e; ++i)
2415 opState.
regions.push_back(std::make_unique<Region>());
2420 readState.curBlock->push_back(op);
2431 if (resultIdxToUseListMap.has_value()) {
2433 if (resultIdxToUseListMap->contains(idx)) {
2435 resultIdxToUseListMap->at(idx));
2442 LogicalResult BytecodeReader::Impl::parseRegion(RegionReadState &readState) {
2443 EncodingReader &reader = *readState.reader;
2447 if (
failed(reader.parseVarInt(numBlocks)))
2456 if (
failed(reader.parseVarInt(numValues)))
2458 readState.numValues = numValues;
2462 readState.curBlocks.clear();
2463 readState.curBlocks.reserve(numBlocks);
2464 for (uint64_t i = 0; i < numBlocks; ++i) {
2465 readState.curBlocks.push_back(
new Block());
2466 readState.curRegion->push_back(readState.curBlocks.back());
2470 valueScopes.back().push(readState);
2473 readState.curBlock = readState.curRegion->begin();
2474 return parseBlockHeader(reader, readState);
2478 BytecodeReader::Impl::parseBlockHeader(EncodingReader &reader,
2479 RegionReadState &readState) {
2481 if (
failed(reader.parseVarIntWithFlag(readState.numOpsRemaining, hasArgs)))
2485 if (hasArgs &&
failed(parseBlockArguments(reader, &*readState.curBlock)))
2492 uint8_t hasUseListOrders = 0;
2493 if (hasArgs &&
failed(reader.parseByte(hasUseListOrders)))
2496 if (!hasUseListOrders)
2499 Block &blk = *readState.curBlock;
2500 auto argIdxToUseListMap =
2502 if (
failed(argIdxToUseListMap) || argIdxToUseListMap->empty())
2506 if (argIdxToUseListMap->contains(idx))
2508 argIdxToUseListMap->at(idx));
2514 LogicalResult BytecodeReader::Impl::parseBlockArguments(EncodingReader &reader,
2518 if (
failed(reader.parseVarInt(numArgs)))
2523 argTypes.reserve(numArgs);
2524 argLocs.reserve(numArgs);
2534 if (
failed(reader.parseVarIntWithFlag(typeIdx, hasLoc)) ||
2535 !(argType = attrTypeReader.resolveType(typeIdx)))
2545 argTypes.push_back(argType);
2546 argLocs.push_back(argLoc);
2556 Value BytecodeReader::Impl::parseOperand(EncodingReader &reader) {
2557 std::vector<Value> &values = valueScopes.back().values;
2558 Value *value =
nullptr;
2564 *value = createForwardRef();
2568 LogicalResult BytecodeReader::Impl::defineValues(EncodingReader &reader,
2570 ValueScope &valueScope = valueScopes.back();
2571 std::vector<Value> &values = valueScope.values;
2573 unsigned &valueID = valueScope.nextValueIDs.back();
2574 unsigned valueIDEnd = valueID + newValues.size();
2575 if (valueIDEnd > values.size()) {
2576 return reader.emitError(
2577 "value index range was outside of the expected range for "
2578 "the parent region, got [",
2579 valueID,
", ", valueIDEnd,
"), but the maximum index was ",
2584 for (
unsigned i = 0, e = newValues.size(); i != e; ++i, ++valueID) {
2585 Value newValue = newValues[i];
2588 if (
Value oldValue = std::exchange(values[valueID], newValue)) {
2589 Operation *forwardRefOp = oldValue.getDefiningOp();
2594 assert(forwardRefOp && forwardRefOp->
getBlock() == &forwardRefOps &&
2595 "value index was already defined?");
2597 oldValue.replaceAllUsesWith(newValue);
2598 forwardRefOp->
moveBefore(&openForwardRefOps, openForwardRefOps.end());
2604 Value BytecodeReader::Impl::createForwardRef() {
2607 if (!openForwardRefOps.empty()) {
2608 Operation *op = &openForwardRefOps.back();
2609 op->
moveBefore(&forwardRefOps, forwardRefOps.end());
2613 return forwardRefOps.back().getResult(0);
2624 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef) {
2628 impl = std::make_unique<Impl>(sourceFileLoc,
config, lazyLoading, buffer,
2634 return impl->read(block, lazyOpsCallback);
2638 return impl->getNumOpsToMaterialize();
2642 return impl->isMaterializable(op);
2647 return impl->materialize(op, lazyOpsCallback);
2652 return impl->finalize(shouldMaterialize);
2656 return buffer.getBuffer().starts_with(
"ML\xefR");
2662 static LogicalResult
2665 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef) {
2671 "input buffer is not an MLIR bytecode file");
2675 buffer, bufferOwnerRef);
2676 return reader.
read(block,
nullptr);
2687 *sourceMgr->getMemoryBuffer(sourceMgr->getMainFileID()), block,
config,
static LogicalResult readBytecodeFileImpl(llvm::MemoryBufferRef buffer, Block *block, const ParserConfig &config, const std::shared_ptr< llvm::SourceMgr > &bufferOwnerRef)
Read the bytecode from the provided memory buffer reference.
static bool isSectionOptional(bytecode::Section::ID sectionID, int version)
Returns true if the given top-level section ID is optional.
static LogicalResult parseResourceGroup(Location fileLoc, bool allowEmpty, EncodingReader &offsetReader, EncodingReader &resourceReader, StringSectionReader &stringReader, T *handler, const std::shared_ptr< llvm::SourceMgr > &bufferOwnerRef, function_ref< StringRef(StringRef)> remapKey={}, function_ref< LogicalResult(StringRef)> processKeyFn={})
static LogicalResult parseDialectGrouping(EncodingReader &reader, MutableArrayRef< std::unique_ptr< BytecodeDialect >> dialects, function_ref< LogicalResult(BytecodeDialect *)> entryCallback)
Parse a single dialect group encoded in the byte stream.
static LogicalResult resolveEntry(EncodingReader &reader, RangeT &entries, uint64_t index, T &entry, StringRef entryStr)
Resolve an index into the given entry list.
static LogicalResult parseEntry(EncodingReader &reader, RangeT &entries, T &entry, StringRef entryStr)
Parse and resolve an index into the given entry list.
static MLIRContext * getContext(OpFoldResult val)
union mlir::linalg::@1243::ArityGroupAndKind::Kind kind
static std::string diag(const llvm::Value &value)
static ParseResult parseRegions(OpAsmParser &parser, OperationState &state, unsigned nRegions=1)
This class represents an opaque handle to a dialect resource entry.
This class represents a single parsed resource entry.
This class represents a processed binary blob of data.
MutableArrayRef< char > getMutableData()
Return a mutable reference to the raw underlying data of this blob.
ArrayRef< char > getData() const
Return the raw underlying data of this blob.
bool isMutable() const
Return if the data of this blob is mutable.
This class represents an instance of a resource parser.
Attributes are known-constant values of operations.
MLIRContext * getContext() const
Return the context this attribute belongs to.
Block represents an ordered list of Operations.
BlockArgument getArgument(unsigned i)
unsigned getNumArguments()
iterator_range< args_iterator > addArguments(TypeRange types, ArrayRef< Location > locs)
Add one argument to the argument list for each type specified in the list.
OpListType & getOperations()
BlockArgListType getArguments()
This class is used to read a bytecode buffer and translate it into MLIR.
LogicalResult materializeAll()
Materialize all operations.
LogicalResult read(Block *block, llvm::function_ref< bool(Operation *)> lazyOps)
Read the bytecode defined within buffer into the given block.
bool isMaterializable(Operation *op)
Impl(Location fileLoc, const ParserConfig &config, bool lazyLoading, llvm::MemoryBufferRef buffer, const std::shared_ptr< llvm::SourceMgr > &bufferOwnerRef)
LogicalResult finalize(function_ref< bool(Operation *)> shouldMaterialize)
Finalize the lazy-loading by calling back with every op that hasn't been materialized to let the clie...
LogicalResult materialize(Operation *op, llvm::function_ref< bool(Operation *)> lazyOpsCallback)
Materialize the provided operation, invoke the lazyOpsCallback on every newly found lazy operation.
int64_t getNumOpsToMaterialize() const
Return the number of ops that haven't been materialized yet.
LogicalResult materialize(Operation *op, llvm::function_ref< bool(Operation *)> lazyOpsCallback=[](Operation *) { return false;})
Materialize the provide operation.
LogicalResult finalize(function_ref< bool(Operation *)> shouldMaterialize=[](Operation *) { return true;})
Finalize the lazy-loading by calling back with every op that hasn't been materialized to let the clie...
BytecodeReader(llvm::MemoryBufferRef buffer, const ParserConfig &config, bool lazyLoad, const std::shared_ptr< llvm::SourceMgr > &bufferOwnerRef={})
Create a bytecode reader for the given buffer.
int64_t getNumOpsToMaterialize() const
Return the number of ops that haven't been materialized yet.
bool isMaterializable(Operation *op)
Return true if the provided op is materializable.
LogicalResult readTopLevel(Block *block, llvm::function_ref< bool(Operation *)> lazyOps=[](Operation *) { return false;})
Read the operations defined within the given memory buffer, containing MLIR bytecode,...
This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine.
This class defines a virtual interface for reading a bytecode stream, providing hooks into the byteco...
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
static FileLineColLoc get(StringAttr filename, unsigned line, unsigned column)
This class represents a diagnostic that is inflight and set to be reported.
InFlightDiagnostic & append(Args &&...args) &
Append arguments to the diagnostic.
Location objects represent source locations information in MLIR.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext * getContext() const
Return the context this location is uniqued in.
MLIRContext is the top-level object for a collection of MLIR operations.
bool allowsUnregisteredDialects()
Return true if we allow to create operation for unregistered dialects.
T * getOrLoadDialect()
Get (or create) a dialect for the given derived dialect type.
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
T::Concept * getInterface() const
Returns an instance of the concept object for the given interface if it was registered to this operat...
bool isRegistered() const
Return if this operation is registered.
Operation is the basic unit of execution within MLIR.
void dropAllReferences()
This drops all operand uses from this operation, which is an essential step in breaking cyclic depend...
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
std::enable_if_t< llvm::function_traits< std::decay_t< FnT > >::num_args==1, RetT > walk(FnT &&callback)
Walk the operation by calling the callback for each nested operation (including this one),...
static Operation * create(Location location, OperationName name, TypeRange resultTypes, ValueRange operands, NamedAttrList &&attributes, OpaqueProperties properties, BlockRange successors, unsigned numRegions)
Create a new Operation with the specific fields.
Block * getBlock()
Returns the operation block that contains this operation.
void moveBefore(Operation *existingOp)
Unlink this operation from its current block and insert it right before existingOp which may be in th...
result_range getResults()
void erase()
Remove this operation from its parent block and delete it.
unsigned getNumResults()
Return the number of results held by this operation.
This class represents a configuration for the MLIR assembly parser.
BlockListType::iterator iterator
This diagnostic handler is a simple RAII class that registers and erases a diagnostic handler on a gi...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
static AsmResourceBlob allocateWithAlign(ArrayRef< char > data, size_t align, AsmResourceBlob::DeleterFn deleter={}, bool dataIsMutable=false)
Create a new unmanaged resource directly referencing the provided data.
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
bool use_empty() const
Returns true if this value has no uses.
void shuffleUseList(ArrayRef< unsigned > indices)
Shuffle the use list order according to the provided indices.
use_range getUses() const
Returns a range of all uses, which is useful for iterating over all uses.
void * getAsOpaquePointer() const
Methods for supporting PointerLikeTypeTraits.
unsigned getNumUses() const
This method computes the number of uses of this Value.
bool hasOneUse() const
Returns true if this value has exactly one use.
use_iterator use_begin() const
static WalkResult advance()
static WalkResult interrupt()
@ kAttrType
This section contains the attributes and types referenced within an IR module.
@ kAttrTypeOffset
This section contains the offsets for the attribute and types within the AttrType section.
@ kIR
This section contains the list of operations serialized into the bytecode, and their nested regions/o...
@ kResource
This section contains the resources of the bytecode.
@ kResourceOffset
This section contains the offsets of resources within the Resource section.
@ kDialect
This section contains the dialects referenced within an IR module.
@ kString
This section contains strings referenced within the bytecode.
@ kDialectVersions
This section contains the versions of each dialect.
@ kProperties
This section contains the properties for the operations.
@ kNumSections
The total number of section types.
static uint64_t getUseID(OperandT &val, unsigned ownerID)
Get the unique ID of a value use.
@ kUseListOrdering
Use-list ordering started to be encoded in version 3.
@ kAlignmentByte
An arbitrary value used to fill alignment padding.
@ kVersion
The current bytecode version.
@ kLazyLoading
Support for lazy-loading of isolated region was added in version 2.
@ kDialectVersioning
Dialects versioning was added in version 1.
@ kElideUnknownBlockArgLocation
Avoid recording unknown locations on block arguments (compression) started in version 4.
@ kNativePropertiesEncoding
Support for encoding properties natively in bytecode instead of merged with the discardable attribute...
@ kMinSupportedVersion
The minimum supported version of the bytecode.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Include the generated interface declarations.
InFlightDiagnostic emitWarning(Location loc)
Utility method to emit a warning message using this location.
StringRef toString(AsmResourceEntryKind kind)
static LogicalResult readResourceHandle(DialectBytecodeReader &reader, FailureOr< T > &value, Ts &&...params)
Helper for resource handle reading that returns LogicalResult.
bool isBytecode(llvm::MemoryBufferRef buffer)
Returns true if the given buffer starts with the magic bytes that signal MLIR bytecode.
const FrozenRewritePatternSet GreedyRewriteConfig config
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
Attribute parseAttribute(llvm::StringRef attrStr, MLIRContext *context, Type type={}, size_t *numRead=nullptr, bool isKnownNullTerminated=false)
This parses a single MLIR attribute to an MLIR context if it was valid.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
Type parseType(llvm::StringRef typeStr, MLIRContext *context, size_t *numRead=nullptr, bool isKnownNullTerminated=false)
This parses a single MLIR type to an MLIR context if it was valid.
AsmResourceEntryKind
This enum represents the different kinds of resource values.
@ Blob
A blob of data with an accompanying alignment.
LogicalResult readBytecodeFile(llvm::MemoryBufferRef buffer, Block *block, const ParserConfig &config)
Read the operations defined within the given memory buffer, containing MLIR bytecode,...
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
This represents an operation in an abstracted form, suitable for use with the builder APIs.
SmallVector< Block *, 1 > successors
Successors of this operation and their respective operands.
SmallVector< Value, 4 > operands
SmallVector< std::unique_ptr< Region >, 1 > regions
Regions that the op will hold.
Attribute propertiesAttr
This Attribute is used to opaquely construct the properties of the operation.
SmallVector< Type, 4 > types
Types of the results of this operation.