21 #include "llvm/ADT/ArrayRef.h"
22 #include "llvm/ADT/ScopeExit.h"
23 #include "llvm/ADT/StringExtras.h"
24 #include "llvm/ADT/StringRef.h"
25 #include "llvm/Support/Endian.h"
26 #include "llvm/Support/MemoryBufferRef.h"
27 #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; }
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;
115 while (isUnaligned(dataIt)) {
117 if (
failed(parseByte(padding)))
120 return emitError(
"expected alignment byte (0xCB), but got: '0x" +
121 llvm::utohexstr(padding) +
"'");
127 if (LLVM_UNLIKELY(isUnaligned(dataIt))) {
128 return emitError(
"expected data iterator aligned to ", alignment,
129 ", but got pointer: '0x" +
130 llvm::utohexstr((uintptr_t)dataIt) +
"'");
137 template <
typename... Args>
144 template <
typename T>
147 return emitError(
"attempting to parse a byte at the end of the bytecode");
148 value =
static_cast<T
>(*dataIt++);
153 if (length > size()) {
154 return emitError(
"attempting to parse ", length,
" bytes when only ",
157 result = {dataIt, length};
164 if (length > size()) {
165 return emitError(
"attempting to parse ", length,
" bytes when only ",
168 memcpy(result, dataIt, length);
176 uint64_t &alignment) {
178 if (
failed(parseVarInt(alignment)) ||
failed(parseVarInt(dataSize)) ||
179 failed(alignTo(alignment)))
181 return parseBytes(dataSize, data);
193 if (
failed(parseByte(result)))
198 if (LLVM_LIKELY(result & 1)) {
206 if (LLVM_UNLIKELY(result == 0)) {
207 llvm::support::ulittle64_t resultLE;
208 if (
failed(parseBytes(
sizeof(resultLE),
209 reinterpret_cast<uint8_t *
>(&resultLE))))
214 return parseMultiByteVarInt(result);
221 if (
failed(parseVarInt(result)))
224 result = (result >> 1) ^ (~(result & 1) + 1);
230 LogicalResult parseVarIntWithFlag(uint64_t &result,
bool &flag) {
231 if (
failed(parseVarInt(result)))
240 if (length > size()) {
241 return emitError(
"attempting to skip ", length,
" bytes when only ",
251 const char *startIt = (
const char *)dataIt;
252 const char *nulIt = (
const char *)memchr(startIt, 0, size());
255 "malformed null-terminated string, no null character found");
257 result = StringRef(startIt, nulIt - startIt);
258 dataIt = (
const uint8_t *)nulIt + 1;
266 uint8_t sectionIDAndHasAlignment;
268 if (
failed(parseByte(sectionIDAndHasAlignment)) ||
269 failed(parseVarInt(length)))
276 bool hasAlignment = sectionIDAndHasAlignment & 0b10000000;
281 return emitError(
"invalid section ID: ",
unsigned(sectionID));
286 if (
failed(parseVarInt(alignment)) ||
failed(alignTo(alignment)))
291 return parseBytes(
static_cast<size_t>(length), sectionData);
294 Location getLoc()
const {
return fileLoc; }
303 LLVM_ATTRIBUTE_NOINLINE
LogicalResult parseMultiByteVarInt(uint64_t &result) {
309 uint32_t numBytes = llvm::countr_zero<uint32_t>(result);
310 assert(numBytes > 0 && numBytes <= 7 &&
311 "unexpected number of trailing zeros in varint encoding");
314 llvm::support::ulittle64_t resultLE(result);
316 parseBytes(numBytes,
reinterpret_cast<uint8_t *
>(&resultLE) + 1)))
321 result = resultLE >> (numBytes + 1);
329 const uint8_t *dataIt;
340 template <
typename RangeT,
typename T>
342 uint64_t index, T &entry,
343 StringRef entryStr) {
344 if (index >= entries.size())
345 return reader.emitError(
"invalid ", entryStr,
" index: ", index);
348 if constexpr (std::is_convertible_v<llvm::detail::ValueOfRange<RangeT>, T>)
349 entry = entries[index];
351 entry = &entries[index];
356 template <
typename RangeT,
typename T>
358 T &entry, StringRef entryStr) {
360 if (
failed(reader.parseVarInt(entryIdx)))
362 return resolveEntry(reader, entries, entryIdx, entry, entryStr);
372 class StringSectionReader {
379 LogicalResult parseString(EncodingReader &reader, StringRef &result) {
380 return parseEntry(reader, strings, result,
"string");
386 LogicalResult parseStringWithFlag(EncodingReader &reader, StringRef &result,
389 if (
failed(reader.parseVarIntWithFlag(entryIdx, flag)))
391 return parseStringAtIndex(reader, entryIdx, result);
396 LogicalResult parseStringAtIndex(EncodingReader &reader, uint64_t index,
398 return resolveEntry(reader, strings, index, result,
"string");
409 EncodingReader stringReader(sectionData, fileLoc);
413 if (
failed(stringReader.parseVarInt(numStrings)))
415 strings.resize(numStrings);
419 size_t stringDataEndOffset = sectionData.size();
420 for (StringRef &
string : llvm::reverse(strings)) {
422 if (
failed(stringReader.parseVarInt(stringSize)))
424 if (stringDataEndOffset < stringSize) {
425 return stringReader.emitError(
426 "string size exceeds the available data size");
430 size_t stringOffset = stringDataEndOffset - stringSize;
432 reinterpret_cast<const char *
>(sectionData.data() + stringOffset),
434 stringDataEndOffset = stringOffset;
439 if ((sectionData.size() - stringReader.size()) != stringDataEndOffset) {
440 return stringReader.emitError(
"unexpected trailing data between the "
441 "offsets for strings and their data");
454 struct BytecodeDialect {
463 Dialect *getLoadedDialect()
const {
465 "expected `load` to be invoked before `getLoadedDialect`");
472 std::optional<Dialect *> dialect;
486 std::unique_ptr<DialectVersion> loadedVersion;
490 struct BytecodeOperationName {
491 BytecodeOperationName(BytecodeDialect *dialect, StringRef name,
492 std::optional<bool> wasRegistered)
493 : dialect(dialect), name(name), wasRegistered(wasRegistered) {}
497 std::optional<OperationName> opName;
500 BytecodeDialect *dialect;
507 std::optional<bool> wasRegistered;
513 EncodingReader &reader,
517 std::unique_ptr<BytecodeDialect> *dialect;
521 if (
failed(reader.parseVarInt(numEntries)))
524 for (uint64_t i = 0; i < numEntries; ++i)
525 if (
failed(entryCallback(dialect->get())))
536 class ResourceSectionReader {
544 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef);
549 return parseEntry(reader, dialectResources, result,
"resource handle");
555 llvm::StringMap<std::string> dialectResourceHandleRenamingMap;
561 EncodingReader &reader, StringSectionReader &stringReader,
562 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef)
563 : key(key), kind(kind), reader(reader), stringReader(stringReader),
564 bufferOwnerRef(bufferOwnerRef) {}
565 ~ParsedResourceEntry()
override =
default;
567 StringRef getKey() const final {
return key; }
575 return emitError() <<
"expected a bool resource entry, but found a "
576 <<
toString(kind) <<
" entry instead";
579 if (
failed(reader.parseByte(value)))
585 return emitError() <<
"expected a string resource entry, but found a "
586 <<
toString(kind) <<
" entry instead";
589 if (
failed(stringReader.parseString(reader,
string)))
595 parseAsBlob(BlobAllocatorFn allocator)
const final {
597 return emitError() <<
"expected a blob resource entry, but found a "
598 <<
toString(kind) <<
" entry instead";
602 if (
failed(reader.parseBlobAndAlignment(data, alignment)))
607 if (bufferOwnerRef) {
608 ArrayRef<char> charData(
reinterpret_cast<const char *
>(data.data()),
616 [bufferOwnerRef = bufferOwnerRef](
void *,
size_t,
size_t) {});
622 assert(llvm::isAddrAligned(llvm::Align(alignment), blob.
getData().data()) &&
624 "blob allocator did not return a properly aligned address");
632 EncodingReader &reader;
633 StringSectionReader &stringReader;
634 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef;
638 template <
typename T>
641 EncodingReader &offsetReader, EncodingReader &resourceReader,
642 StringSectionReader &stringReader, T *handler,
643 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef,
646 uint64_t numResources;
647 if (
failed(offsetReader.parseVarInt(numResources)))
650 for (uint64_t i = 0; i < numResources; ++i) {
653 uint64_t resourceOffset;
655 if (
failed(stringReader.parseString(offsetReader, key)) ||
656 failed(offsetReader.parseVarInt(resourceOffset)) ||
657 failed(offsetReader.parseByte(kind)) ||
658 failed(resourceReader.parseBytes(resourceOffset, data)))
662 if ((processKeyFn &&
failed(processKeyFn(key))))
667 if (allowEmpty && data.empty())
675 EncodingReader entryReader(data, fileLoc);
677 ParsedResourceEntry entry(key, kind, entryReader, stringReader,
679 if (
failed(handler->parseResource(entry)))
681 if (!entryReader.empty()) {
682 return entryReader.emitError(
683 "unexpected trailing bytes in resource entry '", key,
"'");
694 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef) {
695 EncodingReader resourceReader(sectionData, fileLoc);
696 EncodingReader offsetReader(offsetSectionData, fileLoc);
699 uint64_t numExternalResourceGroups;
700 if (
failed(offsetReader.parseVarInt(numExternalResourceGroups)))
705 auto parseGroup = [&](
auto *handler,
bool allowEmpty =
false,
707 auto resolveKey = [&](StringRef key) -> StringRef {
708 auto it = dialectResourceHandleRenamingMap.find(key);
709 if (it == dialectResourceHandleRenamingMap.end())
715 stringReader, handler, bufferOwnerRef, resolveKey,
720 for (uint64_t i = 0; i < numExternalResourceGroups; ++i) {
722 if (
failed(stringReader.parseString(offsetReader, key)))
729 emitWarning(fileLoc) <<
"ignoring unknown external resources for '" << key
733 if (
failed(parseGroup(handler)))
739 while (!offsetReader.empty()) {
740 std::unique_ptr<BytecodeDialect> *dialect;
742 failed((*dialect)->load(dialectReader, ctx)))
744 Dialect *loadedDialect = (*dialect)->getLoadedDialect();
745 if (!loadedDialect) {
746 return resourceReader.emitError()
747 <<
"dialect '" << (*dialect)->name <<
"' is unknown";
749 const auto *handler = dyn_cast<OpAsmDialectInterface>(loadedDialect);
751 return resourceReader.emitError()
752 <<
"unexpected resources for dialect '" << (*dialect)->name <<
"'";
756 auto processResourceKeyFn = [&](StringRef key) ->
LogicalResult {
758 handler->declareResource(key);
760 return resourceReader.emitError()
761 <<
"unknown 'resource' key '" << key <<
"' for dialect '"
762 << (*dialect)->name <<
"'";
764 dialectResourceHandleRenamingMap[key] = handler->getResourceKey(*handle);
765 dialectResources.push_back(*handle);
771 if (
failed(parseGroup(handler,
true, processResourceKeyFn)))
786 class AttrTypeReader {
788 template <
typename T>
793 BytecodeDialect *dialect =
nullptr;
796 bool hasCustomEncoding =
false;
800 using AttrEntry = Entry<Attribute>;
801 using TypeEntry = Entry<Type>;
804 AttrTypeReader(StringSectionReader &stringReader,
805 ResourceSectionReader &resourceReader,
806 const llvm::StringMap<BytecodeDialect *> &dialectsMap,
807 uint64_t &bytecodeVersion,
Location fileLoc,
809 : stringReader(stringReader), resourceReader(resourceReader),
810 dialectsMap(dialectsMap), fileLoc(fileLoc),
811 bytecodeVersion(bytecodeVersion), parserConfig(config) {}
821 Attribute resolveAttribute(
size_t index) {
824 Type resolveType(
size_t index) {
return resolveEntry(types, index,
"Type"); }
829 if (
failed(reader.parseVarInt(attrIdx)))
831 result = resolveAttribute(attrIdx);
838 if (
failed(reader.parseVarIntWithFlag(attrIdx, flag)))
842 result = resolveAttribute(attrIdx);
848 if (
failed(reader.parseVarInt(typeIdx)))
850 result = resolveType(typeIdx);
854 template <
typename T>
859 if ((result = dyn_cast<T>(baseResult)))
861 return reader.emitError(
"expected attribute of type: ",
862 llvm::getTypeName<T>(),
", but got: ", baseResult);
867 template <
typename T>
869 StringRef entryType);
873 template <
typename T>
874 LogicalResult parseAsmEntry(T &result, EncodingReader &reader,
875 StringRef entryType);
879 template <
typename T>
880 LogicalResult parseCustomEntry(Entry<T> &entry, EncodingReader &reader,
881 StringRef entryType);
885 StringSectionReader &stringReader;
889 ResourceSectionReader &resourceReader;
893 const llvm::StringMap<BytecodeDialect *> &dialectsMap;
903 uint64_t &bytecodeVersion;
911 DialectReader(AttrTypeReader &attrTypeReader,
912 StringSectionReader &stringReader,
913 ResourceSectionReader &resourceReader,
914 const llvm::StringMap<BytecodeDialect *> &dialectsMap,
915 EncodingReader &reader, uint64_t &bytecodeVersion)
916 : attrTypeReader(attrTypeReader), stringReader(stringReader),
917 resourceReader(resourceReader), dialectsMap(dialectsMap),
918 reader(reader), bytecodeVersion(bytecodeVersion) {}
921 return reader.emitError(msg);
925 getDialectVersion(StringRef dialectName)
const override {
927 auto dialectEntry = dialectsMap.find(dialectName);
928 if (dialectEntry == dialectsMap.end())
934 dialectEntry->getValue()->loadedVersion ==
nullptr)
936 return dialectEntry->getValue()->loadedVersion.get();
941 uint64_t getBytecodeVersion()
const override {
return bytecodeVersion; }
943 DialectReader withEncodingReader(EncodingReader &encReader)
const {
944 return DialectReader(attrTypeReader, stringReader, resourceReader,
945 dialectsMap, encReader, bytecodeVersion);
948 Location getLoc()
const {
return reader.getLoc(); }
955 return attrTypeReader.parseAttribute(reader, result);
958 return attrTypeReader.parseOptionalAttribute(reader, result);
961 return attrTypeReader.parseType(reader, result);
966 if (
failed(resourceReader.parseResourceHandle(reader, handle)))
976 return reader.parseVarInt(result);
980 uint64_t unsignedResult;
981 if (
failed(reader.parseSignedVarInt(unsignedResult)))
983 result =
static_cast<int64_t
>(unsignedResult);
991 if (
failed(reader.parseByte(value)))
993 return APInt(bitWidth, value);
997 if (bitWidth <= 64) {
999 if (
failed(reader.parseSignedVarInt(value)))
1001 return APInt(bitWidth, value);
1006 uint64_t numActiveWords;
1007 if (
failed(reader.parseVarInt(numActiveWords)))
1010 for (uint64_t i = 0; i < numActiveWords; ++i)
1011 if (
failed(reader.parseSignedVarInt(words[i])))
1013 return APInt(bitWidth, words);
1017 readAPFloatWithKnownSemantics(
const llvm::fltSemantics &semantics)
override {
1019 readAPIntWithKnownWidth(APFloat::getSizeInBits(semantics));
1022 return APFloat(semantics, *intVal);
1026 return stringReader.parseString(reader, result);
1032 if (
failed(reader.parseVarInt(dataSize)) ||
1033 failed(reader.parseBytes(dataSize, data)))
1035 result =
llvm::ArrayRef(
reinterpret_cast<const char *
>(data.data()),
1041 return reader.parseByte(result);
1045 AttrTypeReader &attrTypeReader;
1046 StringSectionReader &stringReader;
1047 ResourceSectionReader &resourceReader;
1048 const llvm::StringMap<BytecodeDialect *> &dialectsMap;
1049 EncodingReader &reader;
1050 uint64_t &bytecodeVersion;
1054 class PropertiesSectionReader {
1058 if (sectionData.empty())
1060 EncodingReader propReader(sectionData, fileLoc);
1062 if (
failed(propReader.parseVarInt(count)))
1065 if (
failed(propReader.parseBytes(propReader.size(), propertiesBuffers)))
1068 EncodingReader offsetsReader(propertiesBuffers, fileLoc);
1069 offsetTable.reserve(count);
1070 for (
auto idx : llvm::seq<int64_t>(0, count)) {
1072 offsetTable.push_back(propertiesBuffers.size() - offsetsReader.size());
1075 if (
failed(offsetsReader.parseVarInt(dataSize)) ||
1076 failed(offsetsReader.parseBytes(dataSize, rawProperties)))
1079 if (!offsetsReader.empty())
1080 return offsetsReader.emitError()
1081 <<
"Broken properties section: didn't exhaust the offsets table";
1087 uint64_t propertiesIdx;
1088 if (
failed(dialectReader.readVarInt(propertiesIdx)))
1090 if (propertiesIdx >= offsetTable.size())
1091 return dialectReader.emitError(
"Properties idx out-of-bound for ")
1093 size_t propertiesOffset = offsetTable[propertiesIdx];
1094 if (propertiesIdx >= propertiesBuffers.size())
1095 return dialectReader.emitError(
"Properties offset out-of-bound for ")
1103 EncodingReader reader(propertiesBuffers.drop_front(propertiesOffset),
1107 dialectReader.withEncodingReader(reader).readBlob(rawProperties)))
1111 EncodingReader reader(
1112 StringRef(rawProperties.begin(), rawProperties.size()), fileLoc);
1113 DialectReader propReader = dialectReader.withEncodingReader(reader);
1115 auto *iface = opName->
getInterface<BytecodeOpInterface>();
1117 return iface->readProperties(propReader, opState);
1119 return propReader.emitError(
1120 "has properties but missing BytecodeOpInterface for ")
1138 EncodingReader offsetReader(offsetSectionData, fileLoc);
1141 uint64_t numAttributes, numTypes;
1142 if (
failed(offsetReader.parseVarInt(numAttributes)) ||
1143 failed(offsetReader.parseVarInt(numTypes)))
1145 attributes.resize(numAttributes);
1146 types.resize(numTypes);
1150 uint64_t currentOffset = 0;
1151 auto parseEntries = [&](
auto &&range) {
1152 size_t currentIndex = 0, endIndex = range.size();
1155 auto parseEntryFn = [&](BytecodeDialect *dialect) ->
LogicalResult {
1156 auto &entry = range[currentIndex++];
1159 if (
failed(offsetReader.parseVarIntWithFlag(entrySize,
1160 entry.hasCustomEncoding)))
1164 if (currentOffset + entrySize > sectionData.size()) {
1165 return offsetReader.emitError(
1166 "Attribute or Type entry offset points past the end of section");
1169 entry.data = sectionData.slice(currentOffset, entrySize);
1170 entry.dialect = dialect;
1171 currentOffset += entrySize;
1174 while (currentIndex != endIndex)
1181 if (
failed(parseEntries(attributes)) ||
failed(parseEntries(types)))
1185 if (!offsetReader.empty()) {
1186 return offsetReader.emitError(
1187 "unexpected trailing data in the Attribute/Type offset section");
1193 template <
typename T>
1195 StringRef entryType) {
1196 if (index >= entries.size()) {
1197 emitError(fileLoc) <<
"invalid " << entryType <<
" index: " << index;
1202 Entry<T> &entry = entries[index];
1207 EncodingReader reader(entry.data, fileLoc);
1210 if (entry.hasCustomEncoding) {
1211 if (
failed(parseCustomEntry(entry, reader, entryType)))
1213 }
else if (
failed(parseAsmEntry(entry.entry, reader, entryType))) {
1217 if (!reader.empty()) {
1218 reader.emitError(
"unexpected trailing bytes after " + entryType +
" entry");
1224 template <
typename T>
1225 LogicalResult AttrTypeReader::parseAsmEntry(T &result, EncodingReader &reader,
1226 StringRef entryType) {
1228 if (
failed(reader.parseNullTerminatedString(asmStr)))
1234 if constexpr (std::is_same_v<T, Type>)
1244 if (numRead != asmStr.size()) {
1245 return reader.emitError(
"trailing characters found after ", entryType,
1246 " assembly format: ", asmStr.drop_front(numRead));
1251 template <
typename T>
1252 LogicalResult AttrTypeReader::parseCustomEntry(Entry<T> &entry,
1253 EncodingReader &reader,
1254 StringRef entryType) {
1255 DialectReader dialectReader(*
this, stringReader, resourceReader, dialectsMap,
1256 reader, bytecodeVersion);
1260 if constexpr (std::is_same_v<T, Type>) {
1262 for (
const auto &callback :
1263 parserConfig.getBytecodeReaderConfig().getTypeCallbacks()) {
1265 callback->read(dialectReader, entry.dialect->name, entry.entry)))
1273 reader = EncodingReader(entry.data, reader.getLoc());
1277 for (
const auto &callback :
1278 parserConfig.getBytecodeReaderConfig().getAttributeCallbacks()) {
1280 callback->read(dialectReader, entry.dialect->name, entry.entry)))
1288 reader = EncodingReader(entry.data, reader.getLoc());
1293 if (!entry.dialect->interface) {
1294 return reader.emitError(
"dialect '", entry.dialect->name,
1295 "' does not implement the bytecode interface");
1298 if constexpr (std::is_same_v<T, Type>)
1299 entry.entry = entry.dialect->interface->readType(dialectReader);
1301 entry.entry = entry.dialect->interface->readAttribute(dialectReader);
1303 return success(!!entry.entry);
1312 struct RegionReadState;
1313 using LazyLoadableOpsInfo =
1314 std::list<std::pair<Operation *, RegionReadState>>;
1315 using LazyLoadableOpsMap =
1320 llvm::MemoryBufferRef buffer,
1321 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef)
1322 : config(config), fileLoc(fileLoc), lazyLoading(lazyLoading),
1323 attrTypeReader(stringReader, resourceReader, dialectsMap, version,
1328 "builtin.unrealized_conversion_cast",
ValueRange(),
1330 buffer(buffer), bufferOwnerRef(bufferOwnerRef) {}
1346 this->lazyOpsCallback = lazyOpsCallback;
1347 auto resetlazyOpsCallback =
1348 llvm::make_scope_exit([&] { this->lazyOpsCallback =
nullptr; });
1349 auto it = lazyLoadableOpsMap.find(op);
1350 assert(it != lazyLoadableOpsMap.end() &&
1351 "materialize called on non-materializable op");
1357 while (!lazyLoadableOpsMap.empty()) {
1369 while (!lazyLoadableOps.empty()) {
1370 Operation *op = lazyLoadableOps.begin()->first;
1371 if (shouldMaterialize(op)) {
1378 lazyLoadableOps.pop_front();
1379 lazyLoadableOpsMap.erase(op);
1386 assert(it != lazyLoadableOpsMap.end() &&
1387 "materialize called on non-materializable op");
1388 valueScopes.emplace_back();
1389 std::vector<RegionReadState> regionStack;
1390 regionStack.push_back(std::move(it->getSecond()->second));
1391 lazyLoadableOps.erase(it->getSecond());
1392 lazyLoadableOpsMap.erase(it);
1394 while (!regionStack.empty())
1415 std::optional<bool> &wasRegistered);
1421 template <
typename T>
1423 return attrTypeReader.parseAttribute(reader, result);
1426 return attrTypeReader.parseType(reader, result);
1433 parseResourceSection(EncodingReader &reader,
1442 struct RegionReadState {
1443 RegionReadState(
Operation *op, EncodingReader *reader,
1444 bool isIsolatedFromAbove)
1445 : RegionReadState(op->getRegions(), reader, isIsolatedFromAbove) {}
1447 bool isIsolatedFromAbove)
1448 : curRegion(regions.begin()), endRegion(regions.end()), reader(reader),
1449 isIsolatedFromAbove(isIsolatedFromAbove) {}
1457 EncodingReader *reader;
1458 std::unique_ptr<EncodingReader> owningReader;
1461 unsigned numValues = 0;
1469 uint64_t numOpsRemaining = 0;
1472 bool isIsolatedFromAbove =
false;
1476 LogicalResult parseRegions(std::vector<RegionReadState> ®ionStack,
1477 RegionReadState &readState);
1479 RegionReadState &readState,
1480 bool &isIsolatedFromAbove);
1484 RegionReadState &readState);
1492 Value parseOperand(EncodingReader &reader);
1498 Value createForwardRef();
1506 struct UseListOrderStorage {
1507 UseListOrderStorage(
bool isIndexPairEncoding,
1509 : indices(std::move(indices)),
1510 isIndexPairEncoding(isIndexPairEncoding){};
1517 bool isIndexPairEncoding;
1527 uint64_t rangeSize);
1544 void push(RegionReadState &readState) {
1545 nextValueIDs.push_back(values.size());
1546 values.resize(values.size() + readState.numValues);
1551 void pop(RegionReadState &readState) {
1552 values.resize(values.size() - readState.numValues);
1553 nextValueIDs.pop_back();
1557 std::vector<Value> values;
1576 LazyLoadableOpsInfo lazyLoadableOps;
1577 LazyLoadableOpsMap lazyLoadableOpsMap;
1581 AttrTypeReader attrTypeReader;
1584 uint64_t version = 0;
1591 llvm::StringMap<BytecodeDialect *> dialectsMap;
1595 ResourceSectionReader resourceReader;
1602 StringSectionReader stringReader;
1605 PropertiesSectionReader propertiesReader;
1608 std::vector<ValueScope> valueScopes;
1615 Block forwardRefOps;
1619 Block openForwardRefOps;
1625 llvm::MemoryBufferRef buffer;
1629 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef;
1634 EncodingReader reader(buffer.getBuffer(), fileLoc);
1635 this->lazyOpsCallback = lazyOpsCallback;
1636 auto resetlazyOpsCallback =
1637 llvm::make_scope_exit([&] { this->lazyOpsCallback =
nullptr; });
1640 if (
failed(reader.skipBytes(StringRef(
"ML\xefR").size())))
1643 if (
failed(parseVersion(reader)) ||
1644 failed(reader.parseNullTerminatedString(producer)))
1650 diag.attachNote() <<
"in bytecode version " << version
1651 <<
" produced by: " << producer;
1656 std::optional<ArrayRef<uint8_t>>
1658 while (!reader.empty()) {
1662 if (
failed(reader.parseSection(sectionID, sectionData)))
1666 if (sectionDatas[sectionID]) {
1667 return reader.emitError(
"duplicate top-level section: ",
1670 sectionDatas[sectionID] = sectionData;
1676 return reader.emitError(
"missing data for top-level section: ",
1682 if (
failed(stringReader.initialize(
1688 failed(propertiesReader.initialize(
1697 if (
failed(parseResourceSection(
1703 if (
failed(attrTypeReader.initialize(
1712 LogicalResult BytecodeReader::Impl::parseVersion(EncodingReader &reader) {
1713 if (
failed(reader.parseVarInt(version)))
1719 if (version < minSupportedVersion) {
1720 return reader.emitError(
"bytecode version ", version,
1721 " is older than the current version of ",
1722 currentVersion,
", and upgrade is not supported");
1724 if (version > currentVersion) {
1725 return reader.emitError(
"bytecode version ", version,
1726 " is newer than the current version ",
1731 lazyLoading =
false;
1738 LogicalResult BytecodeDialect::load(
const DialectReader &reader,
1744 return reader.emitError(
"dialect '")
1746 <<
"' is unknown. If this is intended, please call "
1747 "allowUnregisteredDialects() on the MLIRContext, or use "
1748 "-allow-unregistered-dialect with the MLIR tool used.";
1750 dialect = loadedDialect;
1756 if (!versionBuffer.empty()) {
1758 return reader.emitError(
"dialect '")
1760 <<
"' does not implement the bytecode interface, "
1761 "but found a version entry";
1762 EncodingReader encReader(versionBuffer, reader.getLoc());
1763 DialectReader versionReader = reader.withEncodingReader(encReader);
1764 loadedVersion = interface->readVersion(versionReader);
1773 EncodingReader sectionReader(sectionData, fileLoc);
1776 uint64_t numDialects;
1777 if (
failed(sectionReader.parseVarInt(numDialects)))
1779 dialects.resize(numDialects);
1782 for (uint64_t i = 0; i < numDialects; ++i) {
1783 dialects[i] = std::make_unique<BytecodeDialect>();
1787 if (
failed(stringReader.parseString(sectionReader, dialects[i]->name)))
1793 uint64_t dialectNameIdx;
1794 bool versionAvailable;
1795 if (
failed(sectionReader.parseVarIntWithFlag(dialectNameIdx,
1798 if (
failed(stringReader.parseStringAtIndex(sectionReader, dialectNameIdx,
1799 dialects[i]->name)))
1801 if (versionAvailable) {
1803 if (
failed(sectionReader.parseSection(sectionID,
1804 dialects[i]->versionBuffer)))
1807 emitError(fileLoc,
"expected dialect version section");
1811 dialectsMap[dialects[i]->name] = dialects[i].get();
1815 auto parseOpName = [&](BytecodeDialect *dialect) {
1817 std::optional<bool> wasRegistered;
1821 if (
failed(stringReader.parseString(sectionReader, opName)))
1824 bool wasRegisteredFlag;
1825 if (
failed(stringReader.parseStringWithFlag(sectionReader, opName,
1826 wasRegisteredFlag)))
1828 wasRegistered = wasRegisteredFlag;
1830 opNames.emplace_back(dialect, opName, wasRegistered);
1837 if (
failed(sectionReader.parseVarInt(numOps)))
1839 opNames.reserve(numOps);
1841 while (!sectionReader.empty())
1848 BytecodeReader::Impl::parseOpName(EncodingReader &reader,
1849 std::optional<bool> &wasRegistered) {
1850 BytecodeOperationName *opName =
nullptr;
1853 wasRegistered = opName->wasRegistered;
1856 if (!opName->opName) {
1858 DialectReader dialectReader(attrTypeReader, stringReader, resourceReader,
1859 dialectsMap, reader, version);
1866 if (opName->name.empty()) {
1867 if (opName->dialect->getLoadedDialect())
1868 return emitError(fileLoc) <<
"has an empty opname for dialect '"
1869 << opName->dialect->name <<
"'\n";
1871 opName->opName.emplace(opName->dialect->name,
getContext());
1873 opName->opName.emplace((opName->dialect->name +
"." + opName->name).str(),
1877 return *opName->opName;
1887 if (resourceData.has_value() != resourceOffsetData.has_value()) {
1888 if (resourceOffsetData)
1889 return emitError(fileLoc,
"unexpected resource offset section when "
1890 "resource section is not present");
1893 "expected resource offset section when resource section is present");
1901 DialectReader dialectReader(attrTypeReader, stringReader, resourceReader,
1902 dialectsMap, reader, version);
1903 return resourceReader.initialize(fileLoc, config, dialects, stringReader,
1904 *resourceData, *resourceOffsetData,
1905 dialectReader, bufferOwnerRef);
1912 BytecodeReader::Impl::parseUseListOrderForRange(EncodingReader &reader,
1913 uint64_t numResults) {
1915 uint64_t numValuesToRead = 1;
1916 if (numResults > 1 &&
failed(reader.parseVarInt(numValuesToRead)))
1919 for (
size_t valueIdx = 0; valueIdx < numValuesToRead; valueIdx++) {
1920 uint64_t resultIdx = 0;
1921 if (numResults > 1 &&
failed(reader.parseVarInt(resultIdx)))
1925 bool indexPairEncoding;
1926 if (
failed(reader.parseVarIntWithFlag(numValues, indexPairEncoding)))
1930 for (
size_t idx = 0; idx < numValues; idx++) {
1932 if (
failed(reader.parseVarInt(index)))
1934 useListOrders.push_back(index);
1938 map.try_emplace(resultIdx, UseListOrderStorage(indexPairEncoding,
1939 std::move(useListOrders)));
1955 bool hasIncomingOrder =
1960 bool alreadySorted =
true;
1967 item.value(), operationIDs.at(item.value().getOwner()));
1968 alreadySorted &= prevID > currentID;
1969 currentOrder.push_back({item.index(), currentID});
1975 if (alreadySorted && !hasIncomingOrder)
1982 currentOrder.begin(), currentOrder.end(),
1983 [](
auto elem1,
auto elem2) { return elem1.second > elem2.second; });
1985 if (!hasIncomingOrder) {
1990 llvm::map_range(currentOrder, [&](
auto item) {
return item.first; }));
1996 UseListOrderStorage customOrder =
2005 if (customOrder.isIndexPairEncoding) {
2007 if (shuffle.size() & 1)
2012 std::iota(newShuffle.begin(), newShuffle.end(), idx);
2013 for (idx = 0; idx < shuffle.size(); idx += 2)
2014 newShuffle[shuffle[idx]] = shuffle[idx + 1];
2016 shuffle = std::move(newShuffle);
2023 uint64_t accumulator = 0;
2024 for (
const auto &elem : shuffle) {
2025 if (set.contains(elem))
2027 accumulator += elem;
2030 if (numUses != shuffle.size() ||
2031 accumulator != (((numUses - 1) * numUses) >> 1))
2037 currentOrder, [&](
auto item) {
return shuffle[item.first]; }));
2046 unsigned operationID = 0;
2048 [&](
Operation *op) { operationIDs.try_emplace(op, operationID++); });
2050 auto blockWalk = topLevelOp->
walk([
this](
Block *block) {
2052 if (
failed(sortUseListOrder(arg)))
2059 if (
failed(sortUseListOrder(result)))
2064 return failure(blockWalk.wasInterrupted() || resultWalk.wasInterrupted());
2073 EncodingReader reader(sectionData, fileLoc);
2076 std::vector<RegionReadState> regionStack;
2080 regionStack.emplace_back(*moduleOp, &reader,
true);
2081 regionStack.back().curBlocks.push_back(moduleOp->getBody());
2082 regionStack.back().curBlock = regionStack.back().curRegion->begin();
2083 if (
failed(parseBlockHeader(reader, regionStack.back())))
2085 valueScopes.emplace_back();
2086 valueScopes.back().push(regionStack.back());
2089 while (!regionStack.empty())
2092 if (!forwardRefOps.empty()) {
2093 return reader.emitError(
2094 "not all forward unresolved forward operand references");
2098 if (
failed(processUseLists(*moduleOp)))
2099 return reader.emitError(
2100 "parsed use-list orders were invalid and could not be applied");
2103 for (
const std::unique_ptr<BytecodeDialect> &byteCodeDialect : dialects) {
2106 if (!byteCodeDialect->loadedVersion)
2108 if (byteCodeDialect->interface &&
2109 failed(byteCodeDialect->interface->upgradeFromVersion(
2110 *moduleOp, *byteCodeDialect->loadedVersion)))
2119 auto &parsedOps = moduleOp->getBody()->getOperations();
2121 destOps.splice(destOps.end(), parsedOps, parsedOps.begin(), parsedOps.end());
2127 RegionReadState &readState) {
2131 for (; readState.curRegion != readState.endRegion; ++readState.curRegion) {
2137 if (
failed(parseRegion(readState)))
2141 if (readState.curRegion->empty())
2146 EncodingReader &reader = *readState.reader;
2148 while (readState.numOpsRemaining--) {
2151 bool isIsolatedFromAbove =
false;
2153 parseOpWithoutRegions(reader, readState, isIsolatedFromAbove);
2161 if ((*op)->getNumRegions()) {
2162 RegionReadState childState(*op, &reader, isIsolatedFromAbove);
2168 if (
failed(reader.parseSection(sectionID, sectionData)))
2171 return emitError(fileLoc,
"expected IR section for region");
2172 childState.owningReader =
2173 std::make_unique<EncodingReader>(sectionData, fileLoc);
2174 childState.reader = childState.owningReader.get();
2178 if (lazyLoading && (!lazyOpsCallback || !lazyOpsCallback(*op))) {
2179 lazyLoadableOps.emplace_back(*op, std::move(childState));
2180 lazyLoadableOpsMap.try_emplace(*op,
2181 std::prev(lazyLoadableOps.end()));
2185 regionStack.push_back(std::move(childState));
2188 if (isIsolatedFromAbove)
2189 valueScopes.emplace_back();
2195 if (++readState.curBlock == readState.curRegion->end())
2197 if (
failed(parseBlockHeader(reader, readState)))
2202 readState.curBlock = {};
2203 valueScopes.back().pop(readState);
2208 if (readState.isIsolatedFromAbove) {
2209 assert(!valueScopes.empty() &&
"Expect a valueScope after reading region");
2210 valueScopes.pop_back();
2212 assert(!regionStack.empty() &&
"Expect a regionStack after reading region");
2213 regionStack.pop_back();
2218 BytecodeReader::Impl::parseOpWithoutRegions(EncodingReader &reader,
2219 RegionReadState &readState,
2220 bool &isIsolatedFromAbove) {
2222 std::optional<bool> wasRegistered;
2230 if (
failed(reader.parseByte(opMask)))
2244 DictionaryAttr dictAttr;
2255 "Unexpected missing `wasRegistered` opname flag at "
2256 "bytecode version ")
2257 << version <<
" with properties.";
2261 if (wasRegistered) {
2262 DialectReader dialectReader(attrTypeReader, stringReader, resourceReader,
2263 dialectsMap, reader, version);
2265 propertiesReader.read(fileLoc, dialectReader, &*opName, opState)))
2277 uint64_t numResults;
2278 if (
failed(reader.parseVarInt(numResults)))
2280 opState.
types.resize(numResults);
2281 for (
int i = 0, e = numResults; i < e; ++i)
2288 uint64_t numOperands;
2289 if (
failed(reader.parseVarInt(numOperands)))
2291 opState.
operands.resize(numOperands);
2292 for (
int i = 0, e = numOperands; i < e; ++i)
2293 if (!(opState.
operands[i] = parseOperand(reader)))
2300 if (
failed(reader.parseVarInt(numSuccs)))
2303 for (
int i = 0, e = numSuccs; i < e; ++i) {
2312 std::optional<UseListMapT> resultIdxToUseListMap = std::nullopt;
2315 size_t numResults = opState.
types.size();
2316 auto parseResult = parseUseListOrderForRange(reader, numResults);
2319 resultIdxToUseListMap = std::move(*parseResult);
2324 uint64_t numRegions;
2325 if (
failed(reader.parseVarIntWithFlag(numRegions, isIsolatedFromAbove)))
2328 opState.
regions.reserve(numRegions);
2329 for (
int i = 0, e = numRegions; i < e; ++i)
2330 opState.
regions.push_back(std::make_unique<Region>());
2335 readState.curBlock->push_back(op);
2343 if (resultIdxToUseListMap.has_value()) {
2345 if (resultIdxToUseListMap->contains(idx)) {
2347 resultIdxToUseListMap->at(idx));
2354 LogicalResult BytecodeReader::Impl::parseRegion(RegionReadState &readState) {
2355 EncodingReader &reader = *readState.reader;
2359 if (
failed(reader.parseVarInt(numBlocks)))
2368 if (
failed(reader.parseVarInt(numValues)))
2370 readState.numValues = numValues;
2374 readState.curBlocks.clear();
2375 readState.curBlocks.reserve(numBlocks);
2376 for (uint64_t i = 0; i < numBlocks; ++i) {
2377 readState.curBlocks.push_back(
new Block());
2378 readState.curRegion->push_back(readState.curBlocks.back());
2382 valueScopes.back().push(readState);
2385 readState.curBlock = readState.curRegion->begin();
2386 return parseBlockHeader(reader, readState);
2390 BytecodeReader::Impl::parseBlockHeader(EncodingReader &reader,
2391 RegionReadState &readState) {
2393 if (
failed(reader.parseVarIntWithFlag(readState.numOpsRemaining, hasArgs)))
2397 if (hasArgs &&
failed(parseBlockArguments(reader, &*readState.curBlock)))
2404 uint8_t hasUseListOrders = 0;
2405 if (hasArgs &&
failed(reader.parseByte(hasUseListOrders)))
2408 if (!hasUseListOrders)
2411 Block &blk = *readState.curBlock;
2412 auto argIdxToUseListMap =
2414 if (
failed(argIdxToUseListMap) || argIdxToUseListMap->empty())
2418 if (argIdxToUseListMap->contains(idx))
2420 argIdxToUseListMap->at(idx));
2426 LogicalResult BytecodeReader::Impl::parseBlockArguments(EncodingReader &reader,
2430 if (
failed(reader.parseVarInt(numArgs)))
2435 argTypes.reserve(numArgs);
2436 argLocs.reserve(numArgs);
2446 if (
failed(reader.parseVarIntWithFlag(typeIdx, hasLoc)) ||
2447 !(argType = attrTypeReader.resolveType(typeIdx)))
2457 argTypes.push_back(argType);
2458 argLocs.push_back(argLoc);
2467 Value BytecodeReader::Impl::parseOperand(EncodingReader &reader) {
2468 std::vector<Value> &values = valueScopes.back().values;
2469 Value *value =
nullptr;
2475 *value = createForwardRef();
2479 LogicalResult BytecodeReader::Impl::defineValues(EncodingReader &reader,
2481 ValueScope &valueScope = valueScopes.back();
2482 std::vector<Value> &values = valueScope.values;
2484 unsigned &valueID = valueScope.nextValueIDs.back();
2485 unsigned valueIDEnd = valueID + newValues.size();
2486 if (valueIDEnd > values.size()) {
2487 return reader.emitError(
2488 "value index range was outside of the expected range for "
2489 "the parent region, got [",
2490 valueID,
", ", valueIDEnd,
"), but the maximum index was ",
2495 for (
unsigned i = 0, e = newValues.size(); i != e; ++i, ++valueID) {
2496 Value newValue = newValues[i];
2499 if (
Value oldValue = std::exchange(values[valueID], newValue)) {
2500 Operation *forwardRefOp = oldValue.getDefiningOp();
2505 assert(forwardRefOp && forwardRefOp->
getBlock() == &forwardRefOps &&
2506 "value index was already defined?");
2508 oldValue.replaceAllUsesWith(newValue);
2509 forwardRefOp->
moveBefore(&openForwardRefOps, openForwardRefOps.end());
2515 Value BytecodeReader::Impl::createForwardRef() {
2518 if (!openForwardRefOps.empty()) {
2519 Operation *op = &openForwardRefOps.back();
2520 op->
moveBefore(&forwardRefOps, forwardRefOps.end());
2524 return forwardRefOps.back().getResult(0);
2534 llvm::MemoryBufferRef buffer,
const ParserConfig &config,
bool lazyLoading,
2535 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef) {
2539 impl = std::make_unique<Impl>(sourceFileLoc, config, lazyLoading, buffer,
2545 return impl->read(block, lazyOpsCallback);
2549 return impl->getNumOpsToMaterialize();
2553 return impl->isMaterializable(op);
2558 return impl->materialize(op, lazyOpsCallback);
2563 return impl->finalize(shouldMaterialize);
2567 return buffer.getBuffer().startswith(
"ML\xefR");
2576 const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef) {
2582 "input buffer is not an MLIR bytecode file");
2586 buffer, bufferOwnerRef);
2587 return reader.
read(block,
nullptr);
2598 *sourceMgr->getMemoryBuffer(sourceMgr->getMainFileID()), block, config,
static LogicalResult readBytecodeFileImpl(llvm::MemoryBufferRef buffer, Block *block, const ParserConfig &config, const std::shared_ptr< llvm::SourceMgr > &bufferOwnerRef)
Read the bytecode from the provided memory buffer reference.
static bool isSectionOptional(bytecode::Section::ID sectionID, int version)
Returns true if the given top-level section ID is optional.
static LogicalResult parseResourceGroup(Location fileLoc, bool allowEmpty, EncodingReader &offsetReader, EncodingReader &resourceReader, StringSectionReader &stringReader, T *handler, const std::shared_ptr< llvm::SourceMgr > &bufferOwnerRef, function_ref< StringRef(StringRef)> remapKey={}, function_ref< LogicalResult(StringRef)> processKeyFn={})
static LogicalResult parseDialectGrouping(EncodingReader &reader, MutableArrayRef< std::unique_ptr< BytecodeDialect >> dialects, function_ref< LogicalResult(BytecodeDialect *)> entryCallback)
Parse a single dialect group encoded in the byte stream.
static LogicalResult resolveEntry(EncodingReader &reader, RangeT &entries, uint64_t index, T &entry, StringRef entryStr)
Resolve an index into the given entry list.
static LogicalResult parseEntry(EncodingReader &reader, RangeT &entries, T &entry, StringRef entryStr)
Parse and resolve an index into the given entry list.
static MLIRContext * getContext(OpFoldResult val)
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 provides support for representing a failure result, or a valid value of type T.
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.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
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.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
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,...
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
This class represents an efficient way to signal success or failure.
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.
SmallVector< Type, 4 > types
Types of the results of this operation.